Generate types from new contract ABI JSON (#1320)
* generate types from registry * cleanup * merge, rearrange * lint * built out * abi v2 creation * throw on unions * linting * version handling * split functions * cleanup * drop v1 support * special types * changes * requested changes * formatTYpe * rv outdated test * rv union test * codeclimate * codeclimate * codeclimate * codeclimate * codeclimate * review * cleanup encodeTypes * fix option sub * TypeDefInfo.Result
This commit is contained in:
@@ -66,7 +66,7 @@ const infoMapping: Record<TypeDefInfo, (value: TypeDef) => Constructor> = {
|
||||
[TypeDefInfo.Linkage]: (value: TypeDef): Constructor => Linkage.withKey(getSubType(value)),
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
[TypeDefInfo.Null]: (value: TypeDef): Constructor => ClassOf('Null'),
|
||||
[TypeDefInfo.Null]: (_: TypeDef): Constructor => ClassOf('Null'),
|
||||
|
||||
[TypeDefInfo.Option]: (value: TypeDef): Constructor => Option.with(getSubType(value)),
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ function _decodeEnum (value: TypeDef, details: string[] | Record<string, string>
|
||||
}))
|
||||
: Object.entries(details).map(([name, type]): TypeDef =>
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||
getTypeDef(type || 'Null', name)
|
||||
getTypeDef(type || 'Null', { name })
|
||||
);
|
||||
|
||||
return value;
|
||||
@@ -46,7 +46,7 @@ function _decodeSet (value: TypeDef, details: Record<string, number>): TypeDef {
|
||||
|
||||
// decode a struct, set or enum
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
function _decodeStruct (value: TypeDef, type: string, subType: string): TypeDef {
|
||||
function _decodeStruct (value: TypeDef, type: string, _: string): TypeDef {
|
||||
const parsed = JSON.parse(type);
|
||||
const keys = Object.keys(parsed);
|
||||
|
||||
@@ -58,7 +58,7 @@ function _decodeStruct (value: TypeDef, type: string, subType: string): TypeDef
|
||||
|
||||
value.sub = keys.map((name): TypeDef =>
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||
getTypeDef(parsed[name], name)
|
||||
getTypeDef(parsed[name], { name })
|
||||
);
|
||||
|
||||
return value;
|
||||
@@ -66,7 +66,7 @@ function _decodeStruct (value: TypeDef, type: string, subType: string): TypeDef
|
||||
|
||||
// decode a fixed vector, e.g. [u8;32]
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
function _decodeFixedVec (value: TypeDef, type: string, subType: string): TypeDef {
|
||||
function _decodeFixedVec (value: TypeDef, type: string, _: string): TypeDef {
|
||||
const [vecType, _vecLen] = type.substr(1, type.length - 2).split(';');
|
||||
const vecLen = parseInt(_vecLen.trim(), 10);
|
||||
|
||||
@@ -79,7 +79,7 @@ function _decodeFixedVec (value: TypeDef, type: string, subType: string): TypeDe
|
||||
}
|
||||
|
||||
// decode a tuple
|
||||
function _decodeTuple (value: TypeDef, type: string, subType: string): TypeDef {
|
||||
function _decodeTuple (value: TypeDef, _: string, subType: string): TypeDef {
|
||||
value.sub = typeSplit(subType).map((inner): TypeDef =>
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||
getTypeDef(inner)
|
||||
@@ -118,10 +118,15 @@ function extractSubType (type: string, [start, end]: [string, string, TypeDefInf
|
||||
return type.substr(start.length, type.length - start.length - end.length);
|
||||
}
|
||||
|
||||
export function getTypeDef (_type: string, name?: string): TypeDef {
|
||||
interface TypeDefOptions {
|
||||
name?: string;
|
||||
displayName?: string;
|
||||
}
|
||||
|
||||
export function getTypeDef (_type: string, { name, displayName }: TypeDefOptions = {}): TypeDef {
|
||||
// create the type via Type, allowing types to be sanitized
|
||||
const type = sanitize(_type);
|
||||
const value: TypeDef = { info: TypeDefInfo.Plain, name, type };
|
||||
const value: TypeDef = { info: TypeDefInfo.Plain, displayName, name, type };
|
||||
|
||||
const nested = nestedExtraction.find((nested): boolean =>
|
||||
hasWrapper(type, nested)
|
||||
|
||||
@@ -33,11 +33,122 @@ export interface TypeDefExtVecFixed {
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface TypeDefExtEnumDiscriminant {
|
||||
discriminant: number;
|
||||
}
|
||||
|
||||
export interface TypeDef {
|
||||
info: TypeDefInfo;
|
||||
index?: number;
|
||||
ext?: TypeDefExtVecFixed; // add additional here as required
|
||||
displayName?: string;
|
||||
ext?: TypeDefExtVecFixed | TypeDefExtEnumDiscriminant; // add additional here as required
|
||||
name?: string;
|
||||
namespace?: string;
|
||||
params?: TypeDef[];
|
||||
type: string;
|
||||
sub?: TypeDef | TypeDef[];
|
||||
}
|
||||
|
||||
export type TypeIndex = number;
|
||||
|
||||
export type StringIndex = number;
|
||||
|
||||
export enum MetaTypeInfo {
|
||||
BuiltinPlain,
|
||||
BuiltinTuple,
|
||||
BuiltinArray,
|
||||
Enum,
|
||||
ClikeEnum,
|
||||
Struct,
|
||||
TupleStruct,
|
||||
Null
|
||||
}
|
||||
|
||||
export type MetaTypeIdPrimitive = string;
|
||||
|
||||
export type MetaTypeIdTuple = TypeIndex[];
|
||||
|
||||
export interface MetaTypeIdArray {
|
||||
'array.len': number;
|
||||
'array.type': TypeIndex;
|
||||
}
|
||||
|
||||
export interface MetaTypeIdCustom {
|
||||
'custom.name': StringIndex;
|
||||
'custom.namespace'?: StringIndex[];
|
||||
'custom.params'?: TypeIndex[];
|
||||
}
|
||||
|
||||
export type MetaTypeId = MetaTypeIdPrimitive | MetaTypeIdTuple | MetaTypeIdArray | MetaTypeIdCustom;
|
||||
// MetaTypeIdPrimitive | MetaTypeIdTuple | MetaTypeIdArray | MetaTypeIdCustom;
|
||||
// export type MetaTypeId = Record<string, any>;
|
||||
|
||||
export interface MetaTypeDefClikeEnumVariant {
|
||||
name: StringIndex;
|
||||
discriminant: number;
|
||||
}
|
||||
|
||||
export interface MetaTypeDefClikeEnum {
|
||||
'clike_enum.variants': MetaTypeDefClikeEnumVariant[];
|
||||
}
|
||||
|
||||
export type MetaTypeDefBuiltIn = 'builtin';
|
||||
|
||||
export interface MetaTypeDefEnumVariantUnit {
|
||||
'unit_variant.name': StringIndex;
|
||||
}
|
||||
|
||||
export interface MetaTypeDefEnumVariantTupleStruct {
|
||||
'tuple_struct_variant.name': StringIndex;
|
||||
'tuple_struct_variant.types': TypeIndex[];
|
||||
}
|
||||
|
||||
export interface MetaTypeDefEnumVariantStruct {
|
||||
'struct_variant.name': StringIndex;
|
||||
'struct_variant.fields': MetaTypeDefStructField[];
|
||||
}
|
||||
|
||||
export type MetaTypeDefEnumVariant = MetaTypeDefEnumVariantUnit | MetaTypeDefEnumVariantTupleStruct | MetaTypeDefEnumVariantStruct;
|
||||
|
||||
export interface MetaTypeDefEnum {
|
||||
'enum.variants': MetaTypeDefEnumVariant[];
|
||||
}
|
||||
|
||||
export interface MetaTypeDefStructField {
|
||||
name: StringIndex;
|
||||
type: TypeIndex;
|
||||
}
|
||||
|
||||
export type MetaTypeDefUnionField = MetaTypeDefStructField;
|
||||
|
||||
export interface MetaTypeDefStruct {
|
||||
'struct.fields': MetaTypeDefStructField[];
|
||||
}
|
||||
|
||||
export interface MetaTypeDefTupleStruct {
|
||||
'tuple_struct.types': TypeIndex[];
|
||||
}
|
||||
|
||||
export interface MetaTypeDefUnion {
|
||||
'union.fields': MetaTypeDefUnionField[];
|
||||
}
|
||||
|
||||
export type MetaTypeDef = MetaTypeDefBuiltIn | MetaTypeDefClikeEnum | MetaTypeDefEnum | MetaTypeDefStruct | MetaTypeDefTupleStruct | MetaTypeDefUnion;
|
||||
|
||||
export interface MetaType {
|
||||
def: MetaTypeDef;
|
||||
id: MetaTypeId | null;
|
||||
}
|
||||
|
||||
export enum MetaRegistryItem {
|
||||
String,
|
||||
Type,
|
||||
TypeDef
|
||||
}
|
||||
|
||||
export interface MetaRegistryJson {
|
||||
registry: {
|
||||
strings: string[];
|
||||
types: MetaType[];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -25,3 +25,4 @@ export { default as UInt } from './UInt';
|
||||
|
||||
// Type management helper functions
|
||||
export * from './create';
|
||||
export * from './utils/encodeTypes';
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
// Copyright 2017-2019 @polkadot/types authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { TypeDef, TypeDefInfo, TypeDefExtVecFixed } from '../types';
|
||||
|
||||
import { assert } from '@polkadot/util';
|
||||
|
||||
import { getTypeDef } from '../create';
|
||||
|
||||
const SPECIAL_TYPES = ['AccountId', 'AccountIndex', 'Address', 'Balance'];
|
||||
|
||||
export function paramsNotation (outer: string, inner?: string | any[], transform?: (_: any) => string): string {
|
||||
let array;
|
||||
if (inner) {
|
||||
array = Array.isArray(inner) ? inner : [inner];
|
||||
|
||||
if (transform) {
|
||||
array = array.map(transform);
|
||||
}
|
||||
}
|
||||
return `${outer}${array ? `<${array.join(', ')}>` : ''}`;
|
||||
}
|
||||
|
||||
class TypeEncoder {
|
||||
private static enum (typeDef: Pick<TypeDef, any>): string {
|
||||
assert(typeDef.sub && Array.isArray(typeDef.sub), 'Unable to encode Enum type');
|
||||
|
||||
const sub = typeDef.sub as TypeDef[];
|
||||
|
||||
const isClikeEnum = sub.reduce(
|
||||
(bool: boolean, { type }: TypeDef): boolean => bool && type === 'Null',
|
||||
true
|
||||
);
|
||||
|
||||
if (isClikeEnum) {
|
||||
return `[${
|
||||
sub
|
||||
.map(({ name }: TypeDef): string => `"${name}"`)
|
||||
.join(', ')
|
||||
}]`;
|
||||
}
|
||||
|
||||
return this.subTypes(sub, true);
|
||||
}
|
||||
|
||||
private static struct (typeDef: Pick<TypeDef, any>): string {
|
||||
assert(typeDef.sub && Array.isArray(typeDef.sub), 'Unable to encode Struct type');
|
||||
|
||||
const sub = typeDef.sub as TypeDef[];
|
||||
|
||||
return this.subTypes(sub);
|
||||
}
|
||||
|
||||
private static tuple (typeDef: Pick<TypeDef, any>): string {
|
||||
assert(typeDef.sub && Array.isArray(typeDef.sub), 'Unable to encode Tuple type');
|
||||
|
||||
const sub = typeDef.sub as TypeDef[];
|
||||
|
||||
return `(${
|
||||
sub
|
||||
.map((type: TypeDef): string => TypeEncoder.withParams(type))
|
||||
.join(', ')
|
||||
})`;
|
||||
}
|
||||
|
||||
private static vecFixed (typeDef: Pick<TypeDef, any>): string {
|
||||
assert(typeDef.ext, 'Unable to encode VecFixed type');
|
||||
|
||||
const { type, length } = typeDef.ext as TypeDefExtVecFixed;
|
||||
|
||||
return `[${
|
||||
this.withParams(getTypeDef(type))
|
||||
};${
|
||||
length
|
||||
}]`;
|
||||
}
|
||||
|
||||
private static subTypes (sub: TypeDef[], asEnum?: boolean): string {
|
||||
return `{ ${asEnum ? '"_enum": { ' : ''}${
|
||||
sub
|
||||
.map((type: TypeDef): string => `"${type.name}": "${this.withParams(type)}"`)
|
||||
.join(', ')
|
||||
}} }`;
|
||||
}
|
||||
|
||||
private static withParams (typeDef: Pick<TypeDef, any>, outer = typeDef.displayName || typeDef.type): string {
|
||||
const { params } = typeDef;
|
||||
|
||||
return paramsNotation(
|
||||
outer,
|
||||
params,
|
||||
(param: TypeDef) => TypeEncoder.display(param)
|
||||
);
|
||||
}
|
||||
|
||||
public static encode (typeDef: Pick<TypeDef, any>): string {
|
||||
switch (typeDef.info) {
|
||||
case TypeDefInfo.Null: {
|
||||
return '()';
|
||||
}
|
||||
case TypeDefInfo.Plain: {
|
||||
return typeDef.displayName || typeDef.type;
|
||||
}
|
||||
case TypeDefInfo.Compact: {
|
||||
return TypeEncoder.withParams(typeDef, 'Compact');
|
||||
}
|
||||
case TypeDefInfo.DoubleMap: {
|
||||
return TypeEncoder.withParams(typeDef, 'DoubleMap');
|
||||
}
|
||||
case TypeDefInfo.Linkage: {
|
||||
return TypeEncoder.withParams(typeDef, 'Linkage');
|
||||
}
|
||||
case TypeDefInfo.Option: {
|
||||
return TypeEncoder.withParams(typeDef, 'Option');
|
||||
}
|
||||
case TypeDefInfo.Result: {
|
||||
return TypeEncoder.withParams(typeDef, 'Result');
|
||||
}
|
||||
case TypeDefInfo.Vec: {
|
||||
return TypeEncoder.withParams(typeDef, 'Vec');
|
||||
}
|
||||
case TypeDefInfo.Enum: {
|
||||
return TypeEncoder.enum(typeDef);
|
||||
}
|
||||
case TypeDefInfo.Struct: {
|
||||
return TypeEncoder.struct(typeDef);
|
||||
}
|
||||
case TypeDefInfo.Tuple: {
|
||||
return TypeEncoder.tuple(typeDef);
|
||||
}
|
||||
case TypeDefInfo.VecFixed: {
|
||||
return TypeEncoder.vecFixed(typeDef);
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Cannot encode type: ${typeDef}.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static display (typeDef: Pick<TypeDef, any>): string {
|
||||
if (typeDef.displayName) {
|
||||
return TypeEncoder.withParams(typeDef);
|
||||
}
|
||||
|
||||
switch (typeDef.info) {
|
||||
case TypeDefInfo.Struct:
|
||||
case TypeDefInfo.Enum:
|
||||
return TypeEncoder.withParams(typeDef);
|
||||
default:
|
||||
return TypeEncoder.encode(typeDef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function encodeType (typeDef: Pick<TypeDef, any>): string {
|
||||
return TypeEncoder.encode(typeDef);
|
||||
}
|
||||
|
||||
export function displayType (typeDef: Pick<TypeDef, any>): string {
|
||||
return TypeEncoder.display(typeDef);
|
||||
}
|
||||
|
||||
export function withTypeString (typeDef: Pick<TypeDef, any>): Pick<TypeDef, any> {
|
||||
return {
|
||||
...typeDef,
|
||||
type: SPECIAL_TYPES.includes(typeDef.name)
|
||||
? typeDef.name
|
||||
: encodeType(typeDef)
|
||||
};
|
||||
}
|
||||
@@ -5,4 +5,5 @@
|
||||
export { default as compareArray } from './compareArray';
|
||||
export { default as compareMap } from './compareMap';
|
||||
export { default as decodeU8a } from './decodeU8a';
|
||||
export * from './encodeTypes';
|
||||
export * from './mapToTypeMap';
|
||||
|
||||
@@ -23,3 +23,4 @@ assertSingletonPackage('@polkadot/types');
|
||||
|
||||
export * from './codec';
|
||||
export * from './index.types';
|
||||
export { formatType } from './scripts/util/formatting';
|
||||
|
||||
@@ -234,7 +234,7 @@ function generateInterfaces ({ types }: { types: Record<string, any> }, imports:
|
||||
};
|
||||
|
||||
return Object.entries(types).map(([name, type]): [string, string] => {
|
||||
const def = getTypeDef(isString(type) ? type.toString() : JSON.stringify(type), name);
|
||||
const def = getTypeDef(isString(type) ? type.toString() : JSON.stringify(type), { name });
|
||||
|
||||
return [name, generators[def.info](def, imports)];
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import { TypeDef, TypeDefInfo } from '../../codec/types';
|
||||
|
||||
import { getTypeDef } from '../../codec/create';
|
||||
import { paramsNotation } from '../../codec/utils';
|
||||
import { setImports, TypeImports } from './imports';
|
||||
|
||||
export const HEADER = '// Auto-generated via `yarn build:interfaces`, do not edit\n/* eslint-disable @typescript-eslint/no-empty-interface */\n\n';
|
||||
@@ -37,7 +38,7 @@ export function exportType (name = '', base: string): string {
|
||||
* Given the inner `T`, return a `Compact<T>` string
|
||||
*/
|
||||
export function formatCompact (inner: string): string {
|
||||
return `Compact<${inner}>`;
|
||||
return paramsNotation('Compact', inner);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,28 +52,33 @@ export function formatResult (innerOk: string, innerError: string): string {
|
||||
* Given the inner `T`, return a `Option<T>` string
|
||||
*/
|
||||
export function formatOption (inner: string): string {
|
||||
return `Option<${inner}>`;
|
||||
return paramsNotation('Option', inner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the inners `T[]`, return a `ITuple<...T>` string
|
||||
*/
|
||||
export function formatTuple (inners: string[]): string {
|
||||
return `ITuple<[${inners.join(', ')}]>`;
|
||||
return paramsNotation('ITuple', `[${inners.join(', ')}]`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the inner `T`, return a `Vec<T>` string
|
||||
*/
|
||||
export function formatVec (inner: string): string {
|
||||
return `Vec<${inner}>`;
|
||||
return paramsNotation('Vec', inner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Correctly format a given type
|
||||
*/
|
||||
export function formatType (type: string, imports: TypeImports): string {
|
||||
const typeDef = getTypeDef(type);
|
||||
export function formatType (type: string | TypeDef, imports: TypeImports): string {
|
||||
let typeDef;
|
||||
if (typeof type === 'string') {
|
||||
typeDef = getTypeDef(type);
|
||||
} else {
|
||||
typeDef = type;
|
||||
}
|
||||
|
||||
switch (typeDef.info) {
|
||||
case TypeDefInfo.Compact: {
|
||||
@@ -82,7 +88,7 @@ export function formatType (type: string, imports: TypeImports): string {
|
||||
return formatOption(formatType((typeDef.sub as TypeDef).type, imports));
|
||||
}
|
||||
case TypeDefInfo.Plain: {
|
||||
return type;
|
||||
return typeDef.type;
|
||||
}
|
||||
case TypeDefInfo.Vec: {
|
||||
return formatVec(formatType((typeDef.sub as TypeDef).type, imports));
|
||||
|
||||
Reference in New Issue
Block a user