diff --git a/src/codegen.ts b/src/codegen.ts index 25e12df..7ee8da4 100644 --- a/src/codegen.ts +++ b/src/codegen.ts @@ -5,12 +5,14 @@ import { EOSIO_CORE_CLASSES, EOSIO_CORE_TYPES, generateImportStatement, + generateInterface, getCoreImports, } from './codegen/helpers' import {generateNamespace, generateNamespaceName} from './codegen/namespace' import {generateContractClass} from './codegen/contract' import {abiToBlob} from './utils' import { generateStructClasses } from './codegen/structs' +import { generateActionNamesInterface, generateActionsNamespace } from './codegen/interfaces' const printer = ts.createPrinter() @@ -18,8 +20,6 @@ export async function codegen(contractName, abi) { try { const namespaceName = generateNamespaceName(contractName) - console.log({ imports: getCoreImports(abi)}) - const importContractStatement = generateImportStatement( ['ActionOptions', 'Contract as BaseContract', 'ContractArgs', 'PartialBy'], '@wharfkit/contract' @@ -33,16 +33,16 @@ export async function codegen(contractName, abi) { ...getCoreImports(abi), ] - console.log({sessionImports}) - sessionImports.sort() - console.log({sessionImports}) - const importCoreStatement = generateImportStatement( sessionImports, '@wharfkit/session' - ) + ) + + const actionNamesInterface = generateActionNamesInterface(abi) + + const actionsNamespace = generateActionsNamespace(abi) const {classDeclaration} = await generateContractClass(contractName, abi) @@ -102,6 +102,8 @@ export async function codegen(contractName, abi) { const namespaceDeclaration = generateNamespace(namespaceName, [ abiBlobField, abiField, + // actionNamesInterface, + actionsNamespace, classDeclaration, generateNamespace('Types', structDeclarations), ]) diff --git a/src/codegen/contract.ts b/src/codegen/contract.ts index 8f97c22..f1aee98 100644 --- a/src/codegen/contract.ts +++ b/src/codegen/contract.ts @@ -94,7 +94,6 @@ function generateConstructorFunction(contractName): ts.ExpressionStatement { } function generateActionFunction(abi: ABI.Def): ts.MethodDeclaration { - console.log({abi}) const typeParameter = ts.factory.createTypeParameterDeclaration( "T", ts.factory.createUnionTypeNode( diff --git a/src/codegen/helpers.ts b/src/codegen/helpers.ts index dc63c54..4ecb8f8 100644 --- a/src/codegen/helpers.ts +++ b/src/codegen/helpers.ts @@ -143,7 +143,7 @@ export function findCoreType(type: string): string | undefined { } export function findInternalType(type: string, namespace: string | null, abi: ABI.Def): string { - let typeString = removeDecorators(type) + let { type: typeString } = extractDecorator(type) const relevantAbitype = findAbiType(typeString, abi) @@ -189,31 +189,44 @@ function findVariantType(typeString: string, namespace: string | null, abi: ABI. } function findAbiType(typeString: string, abi: ABI.Def): string | undefined { - return abi.types.find( - (abiType) => abiType.new_type_name.toLowerCase() === typeString.toLowerCase() - )?.type + // console.log('findAbiType', {typeString, abi}) + const abiType = abi.structs.find( + (abiType) => { + // console.log({abiType, typeString}) + return abiType.name.toLowerCase() === typeString.toLowerCase() + } + )?.name + + console.log({formattedAbiType: abiType && `Types.${generateStructClassName(abiType)}` }) + + if (abiType) { + return `Types.${generateStructClassName(abiType)}` + } } export function findExternalType(type: string, abi: ABI.Def): string { - let typeString = removeDecorators(type) + let { type: typeString, decorator } = extractDecorator(type) const relevantAbitype = findAbiType(typeString, abi) + console.log({typeString, relevantAbitype}) + if (relevantAbitype) { typeString = relevantAbitype } - return findCoreType(typeString) || capitalize(typeString) + return `${findCoreType(typeString) || capitalize(typeString)}${decorator === '[]' ? '[]' : ''}` } const decorators = ['?', '[]'] -export function removeDecorators(type: string) { +export function extractDecorator(type: string) : { type: string, decorator?: string } { for (const decorator of decorators) { if (type.includes(decorator)) { type = type.replace(decorator, '') - break + + return { type, decorator } } } - return type + return { type } } diff --git a/src/codegen/interfaces.ts b/src/codegen/interfaces.ts new file mode 100644 index 0000000..cb944c3 --- /dev/null +++ b/src/codegen/interfaces.ts @@ -0,0 +1,57 @@ +import { ABI } from "@wharfkit/session"; +import ts from "typescript"; +import { findCoreType, findExternalType } from "./helpers"; +import { getActionFieldFromAbi } from "./structs"; + +export function generateActionNamesInterface(abi: ABI.Def): ts.PropertySignature[] { + // Generate property signatures for each action + return abi.actions.map(action => { + const actionName = String(action.name); + const actionNameCapitalized = actionName.charAt(0).toUpperCase() + actionName.slice(1); + + return ts.factory.createPropertySignature( + undefined, + actionName, + undefined, + ts.factory.createTypeReferenceNode(`ActionParams.${actionNameCapitalized}`, undefined) + ); + }); +} + +export function generateActionInterface(actionStruct, abi): ts.InterfaceDeclaration { + const members = actionStruct.fields.map(field => { + return ts.factory.createPropertySignature( + undefined, + field.name.toLowerCase(), + field.optional ? ts.factory.createToken(ts.SyntaxKind.QuestionToken) : undefined, + ts.factory.createTypeReferenceNode(findExternalType(field.type, abi), undefined) + ); + }); + + return ts.factory.createInterfaceDeclaration( + [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], + actionStruct.structName, + undefined, + undefined, + members + ); +} + +export function generateActionsNamespace(abi: ABI.Def): ts.ModuleDeclaration { + const actionStructsWithFields = getActionFieldFromAbi(abi); + + + const interfaces = abi.actions.map((action) => { + const actionStruct = actionStructsWithFields.find( + actionStructWithField => actionStructWithField.structName === action.type + ); + return generateActionInterface(actionStruct, abi) + }) + + return ts.factory.createModuleDeclaration( + [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], + ts.factory.createIdentifier("ActionParams"), + ts.factory.createModuleBlock(interfaces), + ts.NodeFlags.Namespace + ); +} \ No newline at end of file diff --git a/src/codegen/structs.ts b/src/codegen/structs.ts index 62b9e2a..c899c26 100644 --- a/src/codegen/structs.ts +++ b/src/codegen/structs.ts @@ -1,6 +1,6 @@ import { ABI } from "@wharfkit/session" import ts from "typescript" -import { findInternalType, generateStructClassName, removeDecorators } from "./helpers" +import { findInternalType, generateStructClassName, extractDecorator } from "./helpers" interface FieldType { name: string @@ -13,7 +13,7 @@ interface StructData { } export function generateStructClasses(abi) { - const structs = getFieldTypesFromAbi(abi) + const structs = getActionFieldFromAbi(abi) const orderedStructs = orderStructs(structs) const structMembers: ts.ClassDeclaration[] = [] @@ -25,7 +25,7 @@ export function generateStructClasses(abi) { return structMembers } -export function getFieldTypesFromAbi(abi: any): StructData[] { +export function getActionFieldFromAbi(abi: any): StructData[] { const structTypes: {structName: string; fields: FieldType[]}[] = [] if (abi && abi.structs) { @@ -162,7 +162,7 @@ function orderStructs(structs) { for (const struct of structs) { for (const field of struct.fields) { - const fieldType = removeDecorators(field.type) + const { type: fieldType } = extractDecorator(field.type) if (structNames.includes(fieldType.toLowerCase())) { const dependencyStruct = structs.find((struct) => struct.structName === fieldType.toLowerCase()) diff --git a/test/tmp/rewards.gm.ts b/test/tmp/rewards.gm.ts index 4924c42..a427d20 100644 --- a/test/tmp/rewards.gm.ts +++ b/test/tmp/rewards.gm.ts @@ -18,6 +18,33 @@ export namespace RewardsGm { 'DmVvc2lvOjphYmkvMS4yAAoHYWRkdXNlcgACB2FjY291bnQEbmFtZQZ3ZWlnaHQGdWludDE2BWNsYWltAAIHYWNjb3VudARuYW1lBmFtb3VudAZhc3NldD8GY29uZmlnAAMMdG9rZW5fc3ltYm9sBnN5bWJvbA5vcmFjbGVfYWNjb3VudARuYW1lDG9yYWNsZV9wYWlycw1vcmFjbGVfcGFpcltdCWNvbmZpZ3VyZQADDHRva2VuX3N5bWJvbAZzeW1ib2wOb3JhY2xlX2FjY291bnQEbmFtZQxvcmFjbGVfcGFpcnMNb3JhY2xlX3BhaXJbXQdkZWx1c2VyAAEHYWNjb3VudARuYW1lC29yYWNsZV9wYWlyAAIEbmFtZQRuYW1lCXByZWNpc2lvbgZ1aW50MTYKcHJpY2VfaW5mbwADBHBhaXIGc3RyaW5nBXByaWNlB2Zsb2F0NjQJdGltZXN0YW1wCnRpbWVfcG9pbnQHcmVjZWlwdAADB2FjY291bnQEbmFtZQZhbW91bnQFYXNzZXQGdGlja2VyDHByaWNlX2luZm9bXQp1cGRhdGV1c2VyAAIHYWNjb3VudARuYW1lBndlaWdodAZ1aW50MTYIdXNlcl9yb3cAAwdhY2NvdW50BG5hbWUGd2VpZ2h0BnVpbnQxNgdiYWxhbmNlBWFzc2V0BgAAAOAqrFMyB2FkZHVzZXKVAi0tLQpzcGVjX3ZlcnNpb246ICIwLjIuMCIKdGl0bGU6IEFkZCB1c2VyCnN1bW1hcnk6ICdBZGQgbmV3IHVzZXIge3tub3dyYXAgYWNjb3VudH19JwppY29uOiBodHRwczovL2FsbW9zdC5kaWdpdGFsL2ltYWdlcy9taXNjX2ljb24ucG5nIzZmNWVhOTc4YjA0ZDAzZTAxOGIzNzlhMmJhYzRjMTBiNWE4ZmUwY2Q1ZTZlMTVjODg4MjhkYzk4NmJlOTZjZmYKLS0tCgp7e2FjY291bnR9fSBpcyBhZGRlZCB0byB0aGUgcmV3YXJkcyBzaGFyaW5nIGxpc3Qgd2l0aCB3ZWlnaHQge3t3ZWlnaHR9fS4AAAAAAOlMRAVjbGFpbfYCLS0tCnNwZWNfdmVyc2lvbjogIjAuMi4wIgp0aXRsZTogQ2xhaW0Kc3VtbWFyeTogJ0NsYWltIHJld2FyZHMgZm9yIHt7bm93cmFwIGFjY291bnR9fScKaWNvbjogaHR0cHM6Ly9hbG1vc3QuZGlnaXRhbC9pbWFnZXMvY2xhaW1faWNvbi5wbmcjYmI1OTdmNGFjYzEzMDU5MjU5MTJlMThlN2I0Y2Y3MDhkMWZhZWMyYWE4OGI3YTUzZDg3OTY5ZTA0NTE2OGVjZgotLS0KCnt7I2lmX2hhc192YWx1ZSBhbW91bnR9fQogICAge3thY2NvdW50fX0gY2xhaW1zIHt7YW1vdW50fX0gZnJvbSB0aGVpciByZXdhcmRzIGJhbGFuY2UuCnt7ZWxzZX19CiAgICB7e2FjY291bnR9fSBjbGFpbXMgdGhlaXIgZW50aXJlIHJld2FyZHMgYmFsYW5jZS4Ke3svaWZfaGFzX3ZhbHVlfX0AAFBXM7cmRQljb25maWd1cmUAAAAA4Cqso0oHZGVsdXNlcsQCLS0tCnNwZWNfdmVyc2lvbjogIjAuMi4wIgp0aXRsZTogRGVsZXRlIHVzZXIKc3VtbWFyeTogJ0RlbGV0ZSB1c2VyIHt7bm93cmFwIGFjY291bnR9fScKaWNvbjogaHR0cHM6Ly9hbG1vc3QuZGlnaXRhbC9pbWFnZXMvbWlzY19pY29uLnBuZyM2ZjVlYTk3OGIwNGQwM2UwMThiMzc5YTJiYWM0YzEwYjVhOGZlMGNkNWU2ZTE1Yzg4ODI4ZGM5ODZiZTk2Y2ZmCi0tLQoKe3thY2NvdW50fX0gaXMgaXMgcmVtb3ZlZCBmcm9tIHRoZSByZXdhcmRzIHNoYXJpbmcgbGlzdC4KClVzZXJzIGNhbiBvbmx5IGJlIHJlbW92ZWQgaWYgdGhlaXIgcmV3YXJkcyBiYWxhbmNlIGlzIHplcm8uAAAAIFenkLoHcmVjZWlwdAAAwFVYq2xS1Qp1cGRhdGV1c2VygAItLS0Kc3BlY192ZXJzaW9uOiAiMC4yLjAiCnRpdGxlOiBVcGRhdGUgdXNlcgpzdW1tYXJ5OiAnVXBkYXRlIHVzZXIge3tub3dyYXAgYWNjb3VudH19JwppY29uOiBodHRwczovL2FsbW9zdC5kaWdpdGFsL2ltYWdlcy9taXNjX2ljb24ucG5nIzZmNWVhOTc4YjA0ZDAzZTAxOGIzNzlhMmJhYzRjMTBiNWE4ZmUwY2Q1ZTZlMTVjODg4MjhkYzk4NmJlOTZjZmYKLS0tCgp7e2FjY291bnR9fSBpcyB1cGRhdGVkIHRvIGhhdmUgd2VpZ2h0IHt7d2VpZ2h0fX0uAgAAAAAwtyZFA2k2NAAABmNvbmZpZwAAAAAAfBXWA2k2NAAACHVzZXJfcm93AAAAAA==' ) export const abi = ABI.from(abiBlob) + export namespace ActionParams { + export interface adduser { + account: NameType + weight: UInt16Type + } + export interface claim { + account: NameType + amount: AssetType + } + export interface configure { + token_symbol: Symbol + oracle_account: NameType + oracle_pairs: Types.OraclePair[] + } + export interface deluser { + account: NameType + } + export interface receipt { + account: NameType + amount: AssetType + ticker: Types.PriceInfo[] + } + export interface updateuser { + account: NameType + weight: UInt16Type + } + } export class Contract extends BaseContract { constructor(args: PartialBy) { super({ @@ -62,8 +89,8 @@ export namespace RewardsGm { token_symbol!: Asset.Symbol @Struct.field(Name) oracle_account!: Name - @Struct.field(OraclePair, {array: true}) - oracle_pairs!: OraclePair[] + @Struct.field(Types.OraclePair, {array: true}) + oracle_pairs!: Types.OraclePair[] } @Struct.type('configure') export class Configure extends Struct { @@ -71,8 +98,8 @@ export namespace RewardsGm { token_symbol!: Asset.Symbol @Struct.field(Name) oracle_account!: Name - @Struct.field(OraclePair, {array: true}) - oracle_pairs!: OraclePair[] + @Struct.field(Types.OraclePair, {array: true}) + oracle_pairs!: Types.OraclePair[] } @Struct.type('deluser') export class Deluser extends Struct { @@ -94,8 +121,8 @@ export namespace RewardsGm { account!: Name @Struct.field(Asset) amount!: Asset - @Struct.field(PriceInfo, {array: true}) - ticker!: PriceInfo[] + @Struct.field(Types.PriceInfo, {array: true}) + ticker!: Types.PriceInfo[] } @Struct.type('updateuser') export class Updateuser extends Struct {