Cleanup contracts type registry (#1497)

* Cleanup contracts type registry

* Remove some ! compiler overrides

* More mappy lookups

* Empty check
This commit is contained in:
Jaco Greeff
2019-10-21 16:18:41 +02:00
committed by GitHub
parent 4c90c6158f
commit aed4b3ee6a
5 changed files with 137 additions and 187 deletions
@@ -14,7 +14,7 @@ describe('MetaRegistry', (): void => {
describe('construction', (): void => {
it('initializes from a contract ABI (ERC20)', (): void => {
const metaRegistry = new MetaRegistry(erc20Abi);
fs.writeFile(path.join(__dirname, 'erc20.test.json'), JSON.stringify(metaRegistry.typeDefs, null, 2), function (err): void {
fs.writeFile(path.join(__dirname, '../test/compare/erc20.test.json'), JSON.stringify(metaRegistry.typeDefs, null, 2), function (err): void {
if (err) throw err;
});
@@ -23,7 +23,7 @@ describe('MetaRegistry', (): void => {
it('initializes from a contract ABI (SharedVec)', (): void => {
const metaRegistry = new MetaRegistry(sharedVecAbi);
fs.writeFile(path.join(__dirname, 'shared-vec.test.json'), JSON.stringify(metaRegistry.typeDefs, null, 2), function (err): void {
fs.writeFile(path.join(__dirname, '../test/compare/shared-vec.test.json'), JSON.stringify(metaRegistry.typeDefs, null, 2), function (err): void {
if (err) throw err;
});
+135 -185
View File
@@ -7,134 +7,110 @@ import { MetaRegistryItem, MetaRegistryJson, MetaTypeDefClikeEnum, MetaType, Met
import { assert } from '@polkadot/util';
import { displayType, withTypeString } from '@polkadot/types';
const {
BuiltinPlain,
BuiltinTuple,
BuiltinVec,
BuiltinVecFixed,
ClikeEnum,
Enum,
Struct,
TupleStruct,
Null
} = MetaTypeInfo;
const builtinMap: [(id: any) => boolean, MetaTypeInfo][] = [
[(id: any): boolean => typeof id === 'string', MetaTypeInfo.BuiltinPlain],
[(id: any): boolean => Array.isArray(id), MetaTypeInfo.BuiltinTuple],
[(id: any): boolean => !!(id['array.type']), MetaTypeInfo.BuiltinVecFixed],
[(id: any): boolean => !!(id['slice.type']), MetaTypeInfo.BuiltinVec]
];
const {
String,
Type,
TypeDef: TypeDefItem
} = MetaRegistryItem;
const typeMap: [string, MetaTypeInfo][] = [
['enum.variants', MetaTypeInfo.Enum],
['clike_enum.variants', MetaTypeInfo.ClikeEnum],
['struct.fields', MetaTypeInfo.Struct],
['tuple_struct.types', MetaTypeInfo.TupleStruct]
];
export default class MetaRegistry {
private static detectedType ({ def, id }: MetaType): MetaTypeInfo {
assert(!(def as MetaTypeDefUnion)['union.fields'], 'Invalid union type definition found');
function detectedType ({ def, id }: MetaType): MetaTypeInfo {
assert(!(def as MetaTypeDefUnion)['union.fields'], 'Invalid union type definition found');
let metaTypeInfo = MetaTypeInfo.Null;
if (def === 'builtin') {
if (typeof id === 'string') {
metaTypeInfo = MetaTypeInfo.BuiltinPlain;
}
if (Array.isArray(id)) {
metaTypeInfo = MetaTypeInfo.BuiltinTuple;
}
if ((id as MetaTypeIdVec)['slice.type']) {
metaTypeInfo = MetaTypeInfo.BuiltinVec;
}
if ((id as MetaTypeIdVecFixed)['array.type']) {
metaTypeInfo = MetaTypeInfo.BuiltinVecFixed;
}
}
const lookup = def === 'builtin'
? builtinMap.find(([test]): boolean => test(id))
: typeMap.find(([test]): boolean => !!(def as any)[test]);
if ((def as MetaTypeDefEnum)['enum.variants']) {
metaTypeInfo = MetaTypeInfo.Enum;
}
return lookup
? lookup[1]
: MetaTypeInfo.Null;
}
if ((def as MetaTypeDefClikeEnum)['clike_enum.variants']) {
metaTypeInfo = MetaTypeInfo.ClikeEnum;
}
class MetadataRegistryLookup {
protected _strings: string[] = [];
if ((def as MetaTypeDefStruct)['struct.fields']) {
metaTypeInfo = MetaTypeInfo.Struct;
}
if ((def as MetaTypeDefTupleStruct)['tuple_struct.types']) {
metaTypeInfo = MetaTypeInfo.TupleStruct;
}
return metaTypeInfo;
}
private _strings: string[] = [];
private _types: MetaType[] = [];
protected _types: MetaType[] = [];
public typeDefs: TypeDef[] = [];
public constructor ({ registry: { strings, types } }: MetaRegistryJson) {
this._strings = strings;
this._types = types;
}
protected hasItemAt (index: number, variant: MetaRegistryItem): boolean {
switch (variant) {
case MetaRegistryItem.String:
return this._strings && !!this._strings[index - 1];
case MetaRegistryItem.Type:
return this._types && !!this._types[index - 1];
case MetaRegistryItem.TypeDef:
return this.typeDefs && !!this.typeDefs[index - 1];
}
}
protected itemAt (index: number, variant: MetaRegistryItem): any {
assert(this.hasItemAt(index, variant), `MetaRegistry: Invalid ${variant} index ${index} found in metadata`);
switch (variant) {
case MetaRegistryItem.String:
return this._strings[index - 1];
case MetaRegistryItem.Type:
return this._types[index - 1];
case MetaRegistryItem.TypeDef:
return this.typeDefs[index - 1];
}
}
protected itemsAt (indices: number[], variant: MetaRegistryItem): any[] {
return indices.map((index: number): string => this.itemAt(index, variant));
}
protected stringAt (index: StringIndex): string {
return this.itemAt(index, MetaRegistryItem.String);
}
public stringsAt (indices: StringIndex[]): string[] {
return this.itemsAt(indices, MetaRegistryItem.String);
}
public typeAt (index: TypeIndex): MetaType {
return this.itemAt(index, MetaRegistryItem.Type);
}
public typesAt (indices: TypeIndex[]): MetaType[] {
return this.itemsAt(indices, MetaRegistryItem.Type);
}
public hasTypeDefAt (index: TypeIndex): boolean {
return this.hasItemAt(index, MetaRegistryItem.TypeDef);
}
public typeDefAt (index: TypeIndex, extra: Pick<TypeDef, never> = {}): TypeDef {
return {
...this.itemAt(index, MetaRegistryItem.TypeDef),
...extra
};
}
}
export default class MetaRegistry extends MetadataRegistryLookup {
public constructor (json: MetaRegistryJson) {
super(json);
// Generate TypeDefs for each provided registry type
this._types.forEach((_, index: number): void => this.setTypeDefAtIndex(index + 1));
}
private hasItemAt (index: number, variant: MetaRegistryItem): boolean {
switch (variant) {
case String:
return this._strings && !!this._strings[index - 1];
case Type:
return this._types && !!this._types[index - 1];
case TypeDefItem:
return this.typeDefs && !!this.typeDefs[index - 1];
}
}
private itemAt (index: number, variant: MetaRegistryItem): any {
assert(this.hasItemAt(index, variant), `MetaRegistry: Invalid ${variant} index ${index} found in metadata`);
switch (variant) {
case String:
return this._strings[index - 1];
case Type:
return this._types[index - 1];
case TypeDefItem:
return this.typeDefs[index - 1];
}
}
private itemsAt (indices: number[], variant: MetaRegistryItem): any[] {
return indices.map(
(index: number): string => {
return this.itemAt(index, variant);
}
);
}
public stringAt (index: StringIndex): string {
return this.itemAt(index, String);
}
public stringsAt (indices: StringIndex[]): string[] {
return this.itemsAt(indices, String);
}
public typeAt (index: TypeIndex): MetaType {
return this.itemAt(index, Type);
}
public typesAt (indices: TypeIndex[]): MetaType[] {
return this.itemsAt(indices, Type);
}
public hasTypeDefAt (index: TypeIndex): boolean {
return this.hasItemAt(index, TypeDefItem);
}
public typeDefAt (index: TypeIndex, extra: Pick<TypeDef, never> = {}): TypeDef {
return {
...this.itemAt(index, TypeDefItem),
...extra
};
public setTypeDefAtIndex (typeIndex: TypeIndex): void {
this.typeDefs[typeIndex - 1] = this.typeDefFromMetaType(this.typeAt(typeIndex), typeIndex);
}
private typeDefIdFields ({ id }: MetaType): Pick<TypeDef, never> {
@@ -146,79 +122,73 @@ export default class MetaRegistry {
return {
name: this.stringAt(nameIndex),
...(
namespaceIndices && namespaceIndices.length
? { namespace: this.stringsAt(namespaceIndices).join('::') }
: {}
...(namespaceIndices && namespaceIndices.length
? { namespace: this.stringsAt(namespaceIndices).join('::') }
: {}
),
...(
paramsIndices && paramsIndices.length
? { params: this.typesAt(paramsIndices).map((type): TypeDef => this.typeDefFromMetaType(type)) }
: {}
...(paramsIndices && paramsIndices.length
? { params: this.typesAt(paramsIndices).map((type): TypeDef => this.typeDefFromMetaType(type)) }
: {}
)
};
}
private typeDefDefFields (metaType: MetaType, typeIndex?: TypeIndex): Pick<TypeDef, never> {
let typeDef;
switch (MetaRegistry.detectedType(metaType)) {
case BuiltinPlain:
switch (detectedType(metaType)) {
case MetaTypeInfo.BuiltinPlain:
typeDef = this.typeDefForBuiltinPlain(metaType.id as string);
break;
case BuiltinTuple:
case MetaTypeInfo.BuiltinTuple:
typeDef = this.typeDefForBuiltinTuple(metaType.id as TypeIndex[]);
break;
case BuiltinVec:
case MetaTypeInfo.BuiltinVec:
typeDef = this.typeDefForBuiltinVec(metaType.id as MetaTypeIdVec, typeIndex);
break;
case BuiltinVecFixed:
case MetaTypeInfo.BuiltinVecFixed:
typeDef = this.typeDefForBuiltinVecFixed(metaType.id as MetaTypeIdVecFixed, typeIndex);
break;
case Enum:
case MetaTypeInfo.Enum:
typeDef = this.typeDefForEnum(metaType.def as MetaTypeDefEnum, metaType.id as MetaTypeIdCustom, typeIndex);
break;
case ClikeEnum:
case MetaTypeInfo.ClikeEnum:
typeDef = this.typeDefForClikeEnum(metaType.def as MetaTypeDefClikeEnum);
break;
case Struct:
case MetaTypeInfo.Struct:
typeDef = this.typeDefForStruct(metaType.def as MetaTypeDefStruct);
break;
case TupleStruct:
case MetaTypeInfo.TupleStruct:
typeDef = this.typeDefForTupleStruct(metaType.def as MetaTypeDefTupleStruct);
break;
case Null:
case MetaTypeInfo.Null:
default:
throw new Error(`Invalid type detected at index ${typeIndex}`);
}
return typeDef;
}
public typeDefFromMetaType (metaType: MetaType, typeIndex?: TypeIndex): TypeDef {
const typeDef: TypeDef = {
return withTypeString({
info: TypeDefInfo.Null,
type: '',
...this.typeDefDefFields(metaType, typeIndex),
...this.typeDefIdFields(metaType)
};
return withTypeString(typeDef) as TypeDef;
}
public setTypeDefAtIndex (typeIndex: TypeIndex): void {
const metaType = this.typeAt(typeIndex);
this.typeDefs[typeIndex - 1] = this.typeDefFromMetaType(metaType, typeIndex);
}) as TypeDef;
}
public typeDefFromMetaTypeAt (typeIndex: TypeIndex): TypeDef {
if (!this.hasTypeDefAt(typeIndex)) {
this.setTypeDefAtIndex(typeIndex);
}
return this.typeDefAt(typeIndex)!;
return this.typeDefAt(typeIndex);
}
private typeDefForEnumVariant (variant: MetaTypeDefEnumVariant): Pick<TypeDef, any> {
const { 'unit_variant.name': unitNameIndex } = variant as MetaTypeDefEnumVariantUnit;
if (unitNameIndex) {
return {
info: TypeDefInfo.Plain,
@@ -228,11 +198,13 @@ export default class MetaRegistry {
}
const { 'tuple_struct_variant.name': tupleStructVariantNameIndex } = variant as MetaTypeDefEnumVariantTupleStruct;
if (tupleStructVariantNameIndex) {
return this.typeDefForTupleStruct(variant as MetaTypeDefEnumVariantTupleStruct);
}
const { 'struct_variant.name': structVariantNameIndex } = variant as MetaTypeDefEnumVariantStruct;
if (structVariantNameIndex) {
return this.typeDefForStruct(variant as MetaTypeDefEnumVariantStruct);
}
@@ -252,6 +224,7 @@ export default class MetaRegistry {
private typeDefForBuiltinTuple (id: TypeIndex[]): Pick<TypeDef, never> {
const sub = id.map((tupleTypeIndex: number): TypeDef => this.typeDefFromMetaTypeAt(tupleTypeIndex));
return {
info: TypeDefInfo.Tuple,
sub
@@ -310,25 +283,19 @@ export default class MetaRegistry {
}
private typeDefForClikeEnum (def: MetaTypeDefClikeEnum): Pick<TypeDef, never> {
const sub = def['clike_enum.variants'].map(
({ name: nameIndex, discriminant }): TypeDef => {
return {
ext: { discriminant },
info: TypeDefInfo.Plain,
name: this.stringAt(nameIndex),
type: 'Null'
};
}
);
return {
info: TypeDefInfo.Enum,
sub
sub: def['clike_enum.variants'].map(({ name: nameIndex, discriminant }): TypeDef => ({
ext: { discriminant },
info: TypeDefInfo.Plain,
name: this.stringAt(nameIndex),
type: 'Null'
}))
};
}
public typeDefForOption (id: MetaTypeIdCustom, typeIndex?: TypeIndex): Pick<TypeDef, any> {
assert(id['custom.params']![0], `Invalid Option type defined at index ${typeIndex}`);
assert(id['custom.params'] && id['custom.params'][0], `Invalid Option type defined at index ${typeIndex}`);
return {
info: TypeDefInfo.Option,
@@ -337,7 +304,7 @@ export default class MetaRegistry {
}
public typeDefForResult (id: MetaTypeIdCustom, typeIndex?: TypeIndex): Pick<TypeDef, any> {
assert(id['custom.params']![0] && id['custom.params']![1], `Invalid Result type defined at index ${typeIndex}`);
assert(id['custom.params'] && id['custom.params'][0] && id['custom.params'][1], `Invalid Result type defined at index ${typeIndex}`);
return {
info: TypeDefInfo.Result,
@@ -348,51 +315,34 @@ export default class MetaRegistry {
public typeDefForStruct (def: MetaTypeDefStruct | MetaTypeDefEnumVariantStruct): Pick<TypeDef, any> {
const structFields = (def as MetaTypeDefStruct)['struct.fields'] || (def as MetaTypeDefEnumVariantStruct)['struct_variant.fields'];
const structNameIndex = (def as MetaTypeDefEnumVariantStruct)['struct_variant.name'];
const sub = structFields.map(
(field: MetaTypeDefStructField): TypeDef => {
const { name: nameIndex, type: fieldTypeIndex } = field;
return {
...this.typeDefFromMetaTypeAt(fieldTypeIndex),
name: this.stringAt(nameIndex)
};
}
);
return withTypeString({
info: TypeDefInfo.Struct,
...(
structNameIndex
? {
name: this.stringAt(structNameIndex)
}
: {}
...(structNameIndex
? { name: this.stringAt(structNameIndex) }
: {}
),
sub
sub: structFields.map((field: MetaTypeDefStructField): TypeDef => ({
...this.typeDefFromMetaTypeAt(field.type),
name: this.stringAt(field.name)
}))
});
}
private typeDefForTupleStruct (def: MetaTypeDefTupleStruct | MetaTypeDefEnumVariantTupleStruct): Pick<TypeDef, any> {
const tupleStructTypes = (def as MetaTypeDefTupleStruct)['tuple_struct.types'] || (def as MetaTypeDefEnumVariantTupleStruct)['tuple_struct_variant.types'];
const tupleStructNameIndex = (def as MetaTypeDefEnumVariantTupleStruct)['tuple_struct_variant.name'];
const sub: TypeDef[] = tupleStructTypes.map(
(tupleStructFieldTypeIndex: number, index: number): TypeDef => {
return {
...this.typeDefFromMetaTypeAt(tupleStructFieldTypeIndex),
index
};
}
);
return withTypeString({
info: TypeDefInfo.Tuple,
...(
tupleStructNameIndex
? {
name: this.stringAt(tupleStructNameIndex)
}
: {}
...(tupleStructNameIndex
? { name: this.stringAt(tupleStructNameIndex) }
: {}
),
sub
sub: tupleStructTypes.map((fieldIndex: number, index: number): TypeDef => ({
...this.typeDefFromMetaTypeAt(fieldIndex),
index
}))
});
}
}