Skip to content

Commit

Permalink
chore: got codegen script geenrating correct rewards.gm helper class
Browse files Browse the repository at this point in the history
  • Loading branch information
dafuga committed Aug 19, 2023
1 parent 94b28a6 commit 211e61a
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 76 deletions.
31 changes: 20 additions & 11 deletions src/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@ import * as ts from 'typescript'
import * as prettier from 'prettier'

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'
import {generateStructClasses} from './codegen/structs'
import {generateActionNamesInterface, generateActionsNamespace} from './codegen/interfaces'
import {generateTableMap} from './codegen/maps'

const printer = ts.createPrinter()

Expand All @@ -38,14 +36,14 @@ export async function codegen(contractName, abi) {
const importCoreStatement = generateImportStatement(
sessionImports,
'@wharfkit/session'
)
)

const {classDeclaration} = await generateContractClass(contractName, abi)

const actionNamesInterface = generateActionNamesInterface(abi)

const actionsNamespace = generateActionsNamespace(abi)

const {classDeclaration} = await generateContractClass(contractName, abi)

// Iterate through structs and create struct classes with fields
const structDeclarations = generateStructClasses(abi)

Expand Down Expand Up @@ -98,18 +96,28 @@ export async function codegen(contractName, abi) {
)
)

const tableMap = generateTableMap(abi)

const exportStatement = ts.factory.createExportAssignment(
undefined,
undefined,
false,
ts.factory.createIdentifier(namespaceName)
);

// Generate types namespace
const namespaceDeclaration = generateNamespace(namespaceName, [
abiBlobField,
abiField,
// actionNamesInterface,
actionsNamespace,
classDeclaration,
actionNamesInterface,
actionsNamespace,
generateNamespace('Types', structDeclarations),
tableMap,
])

const sourceFile = ts.factory.createSourceFile(
[importContractStatement, importCoreStatement, namespaceDeclaration],
[importContractStatement, importCoreStatement, namespaceDeclaration, exportStatement],
ts.factory.createToken(ts.SyntaxKind.EndOfFileToken),
ts.NodeFlags.None
)
Expand All @@ -119,5 +127,6 @@ export async function codegen(contractName, abi) {

} catch (e) {
console.error(`An error occurred while generating the contract code: ${e}`)
throw e
}
}
63 changes: 58 additions & 5 deletions src/codegen/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,14 @@ export async function generateContractClass(contractName: string, abi: ABI.Def)

classMembers.push(constructorMember)

const actionMethod = generateActionFunction(abi)
const actionMethod = generateActionMethod(abi)

classMembers.push(actionMethod)

const tableMethod = generateTableMethod(abi)

classMembers.push(tableMethod)


// Construct class declaration
const classDeclaration = generateClassDeclaration('Contract', classMembers, {
Expand Down Expand Up @@ -93,7 +97,7 @@ function generateConstructorFunction(contractName): ts.ExpressionStatement {
)
}

function generateActionFunction(abi: ABI.Def): ts.MethodDeclaration {
function generateActionMethod(abi: ABI.Def): ts.MethodDeclaration {
const typeParameter = ts.factory.createTypeParameterDeclaration(
"T",
ts.factory.createUnionTypeNode(
Expand All @@ -120,7 +124,7 @@ function generateActionFunction(abi: ABI.Def): ts.MethodDeclaration {
undefined,
"data",
undefined,
ts.factory.createTypeReferenceNode("ActionNameParams", [ts.factory.createTypeReferenceNode("T")]),
ts.factory.createTypeReferenceNode("ActionNameParams[T]"),
undefined
);

Expand All @@ -135,7 +139,7 @@ function generateActionFunction(abi: ABI.Def): ts.MethodDeclaration {
);

// 4. Generate the function body.
const functionBody = ts.factory.createBlock([
const methodBody = ts.factory.createBlock([
ts.factory.createReturnStatement(
ts.factory.createCallExpression(
ts.factory.createPropertyAccessExpression(
Expand All @@ -157,6 +161,55 @@ function generateActionFunction(abi: ABI.Def): ts.MethodDeclaration {
[typeParameter],
[nameParameter, dataParameter, optionsParameter],
ts.factory.createTypeReferenceNode("Action"),
functionBody
methodBody
);
}

function generateTableMethod(abi: ABI.Def): ts.MethodDeclaration {
const typeParameter = ts.factory.createTypeParameterDeclaration(
"T",
ts.factory.createUnionTypeNode(
abi.tables.map(table =>
ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral(String(table.name)))
)
)
);

// 3. Create the function parameters.
const nameParameter = ts.factory.createParameterDeclaration(
undefined,
undefined,
undefined,
"name",
undefined,
ts.factory.createTypeReferenceNode("T"),
undefined
);

// 4. Generate the function body.
const methodBody = ts.factory.createBlock([
ts.factory.createReturnStatement(
ts.factory.createCallExpression(
ts.factory.createPropertyAccessExpression(
ts.factory.createSuper(),
ts.factory.createIdentifier("table")
),
undefined,
[ts.factory.createIdentifier("name"), ts.factory.createIdentifier("TableMap[name]")]
)
)
], true);

return ts.factory.createMethodDeclaration(
undefined,
undefined,
undefined,
'table',
undefined,
[typeParameter],
[nameParameter],
undefined,
methodBody
);
}

24 changes: 8 additions & 16 deletions src/codegen/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export function findCoreType(type: string): string | undefined {
}
}

export function findInternalType(type: string, namespace: string | null, abi: ABI.Def): string {
export function findInternalType(type: string, typeNamespace: string | null, abi: ABI.Def): string {
let { type: typeString } = extractDecorator(type)

const relevantAbitype = findAbiType(typeString, abi)
Expand All @@ -151,13 +151,13 @@ export function findInternalType(type: string, namespace: string | null, abi: AB
typeString = relevantAbitype
}

const variantType = findVariantType(typeString, namespace, abi)
const variantType = findVariantType(typeString, typeNamespace, abi)

if (variantType) {
typeString = variantType
}

return formatInternalType(typeString, namespace, abi)
return formatInternalType(typeString, typeNamespace, abi)
}

function formatInternalType(typeString: string, namespace: string | null, abi: ABI.Def): string {
Expand Down Expand Up @@ -188,28 +188,20 @@ function findVariantType(typeString: string, namespace: string | null, abi: ABI.
.join(' | ')
}

function findAbiType(typeString: string, abi: ABI.Def): string | undefined {
// console.log('findAbiType', {typeString, abi})
export function findAbiType(typeString: string, abi: ABI.Def, typeNamespace = ''): string | undefined {
const abiType = abi.structs.find(
(abiType) => {
// console.log({abiType, typeString})
return abiType.name.toLowerCase() === typeString.toLowerCase()
}
(abiType) => abiType.name === typeString
)?.name

console.log({formattedAbiType: abiType && `Types.${generateStructClassName(abiType)}` })

if (abiType) {
return `Types.${generateStructClassName(abiType)}`
return `${typeNamespace}${generateStructClassName(abiType)}`
}
}

export function findExternalType(type: string, abi: ABI.Def): string {
export function findExternalType(type: string, abi: ABI.Def, typeNamespace?: string): string {
let { type: typeString, decorator } = extractDecorator(type)

const relevantAbitype = findAbiType(typeString, abi)

console.log({typeString, relevantAbitype})
const relevantAbitype = findAbiType(typeString, abi, typeNamespace)

if (relevantAbitype) {
typeString = relevantAbitype
Expand Down
26 changes: 17 additions & 9 deletions src/codegen/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,45 @@
import { ABI } from "@wharfkit/session";
import ts from "typescript";
import { findCoreType, findExternalType } from "./helpers";
import { capitalize } from "../utils";
import { findExternalType } from "./helpers";
import { getActionFieldFromAbi } from "./structs";

export function generateActionNamesInterface(abi: ABI.Def): ts.PropertySignature[] {
export function generateActionNamesInterface(abi: ABI.Def): ts.InterfaceDeclaration {
// Generate property signatures for each action
return abi.actions.map(action => {
const members = abi.actions.map(action => {
const actionName = String(action.name);
const actionNameCapitalized = actionName.charAt(0).toUpperCase() + actionName.slice(1);
const actionNameCapitalized = capitalize(actionName);

return ts.factory.createPropertySignature(
undefined,
actionName,
undefined,
ts.factory.createTypeReferenceNode(`ActionParams.${actionNameCapitalized}`, undefined)
ts.factory.createTypeReferenceNode(`ActionParams.${actionNameCapitalized}`)
);
});

return ts.factory.createInterfaceDeclaration(
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
"ActionNameParams",
undefined,
undefined,
members
);
}

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)
field.type.includes('?') ? ts.factory.createToken(ts.SyntaxKind.QuestionToken) : undefined,
ts.factory.createTypeReferenceNode(findExternalType(field.type, abi, 'Types.'), undefined)
);
});

return ts.factory.createInterfaceDeclaration(
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
actionStruct.structName,
capitalize(actionStruct.structName),
undefined,
undefined,
members
Expand All @@ -40,7 +49,6 @@ export function generateActionInterface(actionStruct, abi): ts.InterfaceDeclarat
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
Expand Down
30 changes: 30 additions & 0 deletions src/codegen/maps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { ABI } from '@wharfkit/session';
import * as ts from 'typescript';
import { findAbiType } from './helpers';

export function generateTableMap(abi: ABI.Def): ts.VariableStatement {
// Map over tables to create the object properties
const tableProperties = abi.tables.map(table =>
ts.factory.createPropertyAssignment(
String(table.name),
ts.factory.createIdentifier(findAbiType(table.type, abi, 'Types.') || table.type)
)
);

// Create the TableMap structure
const tableMap = ts.factory.createObjectLiteralExpression(tableProperties, true);

// Declare the variable
return ts.factory.createVariableStatement(
undefined,
ts.factory.createVariableDeclarationList(
[ts.factory.createVariableDeclaration(
ts.factory.createIdentifier('TableMap'),
undefined,
undefined,
tableMap
)],
ts.NodeFlags.Const
)
);
}
3 changes: 2 additions & 1 deletion src/codegen/structs.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ABI } from "@wharfkit/session"
import ts from "typescript"
import { capitalize } from "../utils"
import { findInternalType, generateStructClassName, extractDecorator } from "./helpers"

interface FieldType {
Expand Down Expand Up @@ -34,7 +35,7 @@ export function getActionFieldFromAbi(abi: any): StructData[] {

for (const field of struct.fields) {
fields.push({
name: field.name.charAt(0).toUpperCase() + field.name.slice(1),
name: capitalize(field.name),
type: field.type,
})
}
Expand Down
5 changes: 0 additions & 5 deletions test/data/contracts/mock-rewards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,6 @@ export namespace RewardsGm {
export interface Deluser {
account: NameType
}
export interface OraclePair {
name: NameType
precision: UInt16Type
}
export interface Receipt {
account: NameType
amount: AssetType
Expand Down Expand Up @@ -161,5 +157,4 @@ export namespace RewardsGm {
users: Types.UserRow,
}
}

export default RewardsGm
Loading

0 comments on commit 211e61a

Please sign in to comment.