Skip to content

Commit

Permalink
feat: make codegen tool generic
Browse files Browse the repository at this point in the history
  • Loading branch information
alanrsoares committed Nov 7, 2023
1 parent d04c537 commit 5ec09ba
Showing 1 changed file with 43 additions and 33 deletions.
76 changes: 43 additions & 33 deletions scripts/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ import { capitalize } from '@axelarjs/utils/string';
import fs from 'fs/promises';
import path from 'path';
import prettier from 'prettier';
import { $ } from 'zx';
import { $, glob } from 'zx';

$.verbose = false;

const kebabToPascalCase = convertCase('kebab-case', 'PascalCase');
const pascalToKebabCase = convertCase('PascalCase', 'kebab-case');

type ABIInputItem = {
Expand Down Expand Up @@ -57,44 +56,48 @@ const CONTRACT_FOLDERS = ['InterchainTokenService.sol', 'InterchainTokenFactory.
/**
* Extracts the contract formatted name and path from the folder name
*
* @param folder
* @param folderPath
*/
function extractContractNameAndPath(folder: string) {
if (folder.endsWith('.sol')) {
const [pascalName] = folder.split('.');

return {
pascalName,
kebabName: pascalToKebabCase(pascalName ?? ''),
abiPath: path.join(folder, `${pascalName}.json`),
};
}

const pascalName = kebabToPascalCase(folder);
function extractContractNameAndPath(folderPath: string) {
const pascalName = path.basename(folderPath).replace(/.sol$/, '');

return {
pascalName,
kebabName: folder,
abiPath: path.join(folder, `${pascalName}.sol`, `${pascalName}.json`),
kebabName: pascalToKebabCase(pascalName),
abiPath: path.join(folderPath, `${pascalName}.json`),
};
}

async function main(contractFolders: string[]) {
async function main(
contractFolder: string,
options: {
excludePatterns?: string[];
outputFolder?: string;
}
) {
const contractFolders = await glob(`${contractFolder}/**/**.sol`, {
onlyDirectories: true,
ignore: options.excludePatterns?.flatMap((pattern) => [`${pattern}/**`, `${contractFolder}/${pattern}/**`, `**/${pattern}/**`]),
});

for (const contractFolder of contractFolders) {
const { pascalName, kebabName, abiPath } = extractContractNameAndPath(contractFolder);
const { pascalName, abiPath } = extractContractNameAndPath(contractFolder);

const abiJsonFullPath = path.join('artifacts', 'contracts', abiPath);
const { stdout: abiFileJson } = await $`cat ./${abiPath}`;

const { stdout: abiFileJson } = await $`cat ./${abiJsonFullPath}`;
if (!abiFileJson) {
console.log(`ABI file not found: ${abiPath}`);
continue;
}

const GENERATED_DISCLAIMER = `
/* eslint-disable @typescript-eslint/no-explicit-any */
/**
* This file was generated by scripts/codegen.ts
*
* Original abi file:
* - ${abiJsonFullPath}
*
*
* Original abi file:
* - ${abiPath}
*
* DO NOT EDIT MANUALLY
*/
`;
Expand All @@ -106,15 +109,15 @@ async function main(contractFolders: string[]) {

const abiJsonFile = `${JSON.stringify({ contractName, abi }, null, 2)}`;

const outputPath = path.join('typescript', 'contracts', kebabName);
const outputPath = path.join(path.resolve(options.outputFolder ?? ''), pascalName);

// only generate args file if there are functions with inputs
const abiFns = abi.filter((x) => x.type === 'function' && x.inputs.length && x.inputs.every((input) => input.name));

const argsFile = `
import { encodeFunctionData } from "viem";
import ABI_FILE from "./${kebabName}.abi";
import ABI_FILE from "./${pascalName}.abi";
${abiFns
.map(({ name, inputs }) => {
Expand All @@ -127,12 +130,12 @@ async function main(contractFolders: string[]) {
return `
export type ${typeName} = {${argsType}}
/**
* Factory function for ${pascalName}.${name} function args
*/
export const encode${pascalName}${fnName}Args = ({${argNames}}: ${typeName}) => [${argNames}] as const;
/**
* Encoder function for ${pascalName}.${name} function data
*/
Expand All @@ -155,16 +158,17 @@ async function main(contractFolders: string[]) {

const files = [
{
name: `${kebabName}.abi.ts`,
name: `${pascalName}.abi.ts`,
content: abiFile,
parser: 'babel-ts',
},
{
name: `${kebabName}.args.ts`,
name: `${pascalName}.args.ts`,
content: argsFile,
parser: 'babel-ts',
excluded: !abiFns.length,
},
];
].filter(({ excluded }) => !excluded);

// write files
await Promise.all(
Expand All @@ -183,7 +187,13 @@ async function main(contractFolders: string[]) {
}
}

main(CONTRACT_FOLDERS).catch((err) => {
const CONTRACT_FOLDER = 'artifacts/contracts';
const EXCLUDED_SUBFOLDERS = ['test'];

main(CONTRACT_FOLDER, {
excludePatterns: EXCLUDED_SUBFOLDERS,
outputFolder: 'typescript/contracts',
}).catch((err) => {
console.error(err);
process.exit(1);
});

0 comments on commit 5ec09ba

Please sign in to comment.