mirror of
https://github.com/lux-tel/websites.git
synced 2026-10-30 20:31:36 +00:00
242 lines
7.8 KiB
TypeScript
242 lines
7.8 KiB
TypeScript
import { execSync } from 'child_process';
|
|
import { promises as fs } from 'fs';
|
|
import { join } from 'path';
|
|
|
|
const debug = process.argv.includes('--debug');
|
|
|
|
/**
|
|
* Logger object for logging debug, info, and error messages. Debug messages are only logged when the --debug flag is provided.
|
|
*/
|
|
const logger = {
|
|
debug: debug ? console.debug : () => {},
|
|
info: console.info,
|
|
error: console.error,
|
|
};
|
|
logger.debug('Debugging enabled');
|
|
|
|
const GENERATED_FILE_HEADER = `// This file is generated by the generate-abis script. Do not modify it manually.\n\n`;
|
|
const ABI_DOC_STRING = (contractName: string) =>
|
|
`${GENERATED_FILE_HEADER}/**\n * Generated ABI for the ${contractName} contract.\n */\n`;
|
|
|
|
/**
|
|
* Generates the ABI for a contract and writes it to a file.
|
|
* @param filePath The path to the JSON file containing the contract.
|
|
* @param outputDir The directory to write the generated ABI file to.
|
|
* @returns The name of the generated contract.
|
|
*/
|
|
async function generateABI({ filePath, outputDir }: { filePath: string; outputDir: string }) {
|
|
try {
|
|
const json = await fs.readFile(filePath, 'utf8');
|
|
|
|
const { contractName, abi } = JSON.parse(json);
|
|
|
|
if (!contractName) {
|
|
throw new Error(`Contract name not found! ${filePath}`);
|
|
}
|
|
|
|
if (!abi) {
|
|
throw new Error(`Contract ABI not found! ${filePath} with name: ${contractName}`);
|
|
}
|
|
|
|
// Write the ABI to a file
|
|
logger.debug(`Generating ABI for ${contractName}...`);
|
|
const abiType = `${ABI_DOC_STRING(contractName)}export const ${contractName}Abi = ${JSON.stringify(abi, null, 2)} as const;`;
|
|
await fs.writeFile(join(outputDir, `${contractName}.ts`), abiType);
|
|
logger.info(`ABI for ${contractName} generated successfully!`);
|
|
return contractName;
|
|
} catch (error) {
|
|
logger.error('Error generating ABI:', error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Downloads the repository from the specified GitHub URL to the destination path.
|
|
* If the repository is already downloaded, it uses the cache.
|
|
* @param url The GitHub URL of the repository to download.
|
|
* @param destinationPath The path to download the repository to.
|
|
*/
|
|
async function downloadRepository({
|
|
url,
|
|
destinationPath,
|
|
}: {
|
|
url: string;
|
|
destinationPath: string;
|
|
}) {
|
|
try {
|
|
// check if the repository is already downloaded
|
|
const isRepoDownloaded = await fs
|
|
.access(destinationPath)
|
|
.then(() => true)
|
|
.catch(() => false);
|
|
|
|
if (isRepoDownloaded) {
|
|
logger.info('Repository already downloaded. Using cache...');
|
|
return;
|
|
}
|
|
// Clone the repository
|
|
execSync(`git clone ${url} ${destinationPath}`);
|
|
logger.info('Repository downloaded successfully!');
|
|
execSync(`cd ${destinationPath} && git switch master`);
|
|
} catch (error) {
|
|
logger.error('Error downloading repository:', error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generates contracts.
|
|
* @param destinationPath The path to the downloaded repository.
|
|
* @returns A promise that resolves when the contracts are generated.
|
|
*/
|
|
async function generateContracts({ destinationPath }: { destinationPath: string }) {
|
|
execSync(`cd ${destinationPath} && pnpm yarn install && pnpm yarn build`, {
|
|
stdio: debug ? 'inherit' : 'pipe',
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Generates contract ABIs for the given directory and its subdirectories.
|
|
*
|
|
* @param dir - The directory path to generate contract ABIs for.
|
|
* @param generatedAbis - An array to store the names of the generated ABIs.
|
|
* @param excludeDirs - An array of directories to exclude from ABI generation.
|
|
* @param outputDir - The directory to write the generated ABI files to.
|
|
* @returns A promise that resolves when all contract ABIs have been generated.
|
|
*/
|
|
async function generateContractABIs({
|
|
dir,
|
|
abis = [],
|
|
excludeDirs = [],
|
|
outputDir,
|
|
}: {
|
|
dir: string;
|
|
abis: Array<string>;
|
|
excludeDirs: Array<string>;
|
|
outputDir: string;
|
|
}) {
|
|
try {
|
|
// Get the list of files in the contracts directory
|
|
const files = await fs.readdir(dir);
|
|
|
|
// Generate ABIs for each contract
|
|
for (const file of files) {
|
|
// Check if the directory should be excluded
|
|
if (excludeDirs.includes(file)) {
|
|
logger.debug('Excluding directory:', file);
|
|
continue;
|
|
}
|
|
|
|
const filePath = join(dir, file);
|
|
|
|
if (file.endsWith('.dbg.json')) {
|
|
logger.debug('Skipping debug file:', file);
|
|
continue;
|
|
}
|
|
|
|
logger.debug('Checking file:', filePath);
|
|
if (file.endsWith('.json')) {
|
|
try {
|
|
const name = await generateABI({ filePath, outputDir });
|
|
abis.push(name);
|
|
} catch (error) {
|
|
logger.error(error);
|
|
}
|
|
continue;
|
|
}
|
|
// check if the file is a directory
|
|
const stats = await fs.lstat(filePath);
|
|
if (!stats.isDirectory()) {
|
|
logger.debug('File is not a directory. skipping');
|
|
continue;
|
|
}
|
|
await generateContractABIs({ dir: filePath, abis, excludeDirs, outputDir });
|
|
}
|
|
} catch (error) {
|
|
logger.error('Error generating contract ABIs:', error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generates an ABI index file based on the provided array of ABI names.
|
|
* @param abis An array of ABI names.
|
|
* @param outputDir The directory to write the generated index file to.
|
|
*/
|
|
async function generateAbiIndex({ abis, outputDir }: { abis: Array<string>; outputDir: string }) {
|
|
logger.debug('abis', abis);
|
|
const indexFile = abis
|
|
.map((abi) => `import { ${abi}Abi } from './${abi}';`)
|
|
.join('\n')
|
|
.concat(
|
|
`\n\nexport const Contracts = {\n${abis.map((abi) => `${abi}: ${abi}Abi`).join(',\n')}\n} as const;`
|
|
)
|
|
.concat(`export type ContractWithAbiName = keyof typeof Contracts;`)
|
|
.concat(`export type ContractAbis = typeof Contracts;`)
|
|
.concat(`export {\n${abis.map((abi) => `${abi}Abi,`).join('\n')}\n};`);
|
|
|
|
// Write the index file
|
|
await fs.writeFile(join(outputDir, 'index.ts'), GENERATED_FILE_HEADER.concat(indexFile));
|
|
logger.info('Index file generated successfully!');
|
|
}
|
|
|
|
/**
|
|
* This is the main function that generates the ABIs. It runs when the script is called.
|
|
*/
|
|
async function index() {
|
|
const githubUrl = 'https://github.com/oxen-io/eth-sn-contracts/';
|
|
const url = githubUrl.split('/').filter((str) => str);
|
|
const repoName = url.pop();
|
|
const destinationPath = `./.cache/${repoName}`;
|
|
const contractsPath = join(destinationPath, '/artifacts/contracts');
|
|
const outputDir = './abis';
|
|
const excludeDirs = ['interfaces', 'test'];
|
|
|
|
// Create the output directory
|
|
await fs.mkdir(outputDir, { recursive: true });
|
|
|
|
let cachedHash = '';
|
|
try {
|
|
await fs.access('.cache');
|
|
try {
|
|
cachedHash = await fs.readFile(`./.cache/${repoName}.hash`, 'utf8');
|
|
} catch (error) {
|
|
logger.error('Error reading cached hash:', error);
|
|
}
|
|
} catch (error) {
|
|
logger.debug('.cache directory not found. Skipping cache check');
|
|
}
|
|
|
|
// Download the repository
|
|
await downloadRepository({ url: githubUrl, destinationPath });
|
|
|
|
const commitHash = execSync('git rev-parse HEAD', { cwd: destinationPath }).toString().trim();
|
|
logger.debug('Commit hash:', commitHash);
|
|
await fs.writeFile(`${destinationPath}.hash`, commitHash);
|
|
|
|
// Check if ./abis directory exists and contains files
|
|
const files = await fs.readdir(outputDir);
|
|
if (files.length) {
|
|
if (files.length && commitHash === cachedHash) {
|
|
logger.info('No changes detected. Skipping ABI generation.');
|
|
return;
|
|
} else {
|
|
// write the hash to the cache
|
|
await fs.writeFile(`./.cache/${repoName}.hash`, commitHash);
|
|
}
|
|
}
|
|
|
|
// Generate contracts
|
|
await generateContracts({ destinationPath });
|
|
|
|
// Generate contract ABIs
|
|
const abis: Array<string> = [];
|
|
await generateContractABIs({ dir: contractsPath, abis, excludeDirs, outputDir });
|
|
|
|
// Generate the index file
|
|
await generateAbiIndex({ abis, outputDir });
|
|
|
|
logger.info('ABIs generated successfully!');
|
|
logger.info('Formatting files...');
|
|
execSync('pnpm format');
|
|
}
|
|
|
|
index();
|