Skip to content

Commit

Permalink
chore: generating interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
dafuga committed Aug 18, 2023
1 parent 767ae7b commit 94b28a6
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 27 deletions.
16 changes: 9 additions & 7 deletions src/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@ 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()

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'
Expand All @@ -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)

Expand Down Expand Up @@ -102,6 +102,8 @@ export async function codegen(contractName, abi) {
const namespaceDeclaration = generateNamespace(namespaceName, [
abiBlobField,
abiField,
// actionNamesInterface,
actionsNamespace,
classDeclaration,
generateNamespace('Types', structDeclarations),
])
Expand Down
1 change: 0 additions & 1 deletion src/codegen/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
31 changes: 22 additions & 9 deletions src/codegen/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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 }
}
57 changes: 57 additions & 0 deletions src/codegen/interfaces.ts
Original file line number Diff line number Diff line change
@@ -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
);
}
8 changes: 4 additions & 4 deletions src/codegen/structs.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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[] = []
Expand All @@ -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) {
Expand Down Expand Up @@ -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())
Expand Down
39 changes: 33 additions & 6 deletions test/tmp/rewards.gm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<ContractArgs, 'abi' | 'account'>) {
super({
Expand Down Expand Up @@ -62,17 +89,17 @@ 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 {
@Struct.field(Asset.Symbol)
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 {
Expand All @@ -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 {
Expand Down

0 comments on commit 94b28a6

Please sign in to comment.