sbv2-solana/javascript/solana.js/scripts/generate-client.js

176 lines
5.4 KiB
JavaScript
Executable File

import shell from "shelljs";
import path from "path";
import fs from "fs";
import { execSync } from "child_process";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const projectRoot = path.join(__dirname, "..");
// Super hacky. Some files need to be reset to the previous git state and will be manually managed
const ignoreFiles = [
"./src/generated/types/SwitchboardPermission.ts", // we manually added NONE enumeration
"./src/generated/types/SwitchboardDecimal.ts", // added toBig methods
"./src/generated/types/Lanes.ts", // anchor-client-gen struggles with dual exports
"./src/generated/types/index.ts", // TODO: Need a better way to handle this. anchor-client-gen adds multiple, broken exports (for VRF builder)
"./src/generated/errors/index.ts", // need to revert the program ID check
];
/**
* Fetch a list of filepaths for a given directory and desired file extension
* @param [dirPath] Filesystem path to a directory to search.
* @param [arrayOfFiles] An array of existing file paths for recursive calls
* @param [extensions] Optional, an array of desired extensions with the leading separator '.'
* @throws {String}
* @returns {string[]}
*/
const getAllFiles = (dirPath, arrayOfFiles, extensions) => {
const files = fs.readdirSync(dirPath, "utf8");
arrayOfFiles = arrayOfFiles || [];
files.forEach((file) => {
if (fs.statSync(dirPath + "/" + file).isDirectory()) {
arrayOfFiles = getAllFiles(
dirPath + "/" + file,
arrayOfFiles,
extensions
);
} else {
const ext = path.extname(file);
if (extensions && Array.isArray(extensions) && extensions.includes(ext)) {
arrayOfFiles.push(path.join(dirPath, "/", file));
} else {
arrayOfFiles.push(path.join(dirPath, "/", file));
}
// if (!(extensions === undefined) || extensions.includes(ext)) {
// arrayOfFiles.push(path.join(dirPath, '/', file));
// }
}
});
return arrayOfFiles;
};
async function main() {
shell.cd(projectRoot);
const isDev = process.argv.includes("--dev");
if (!shell.which("anchor")) {
shell.echo(
"Sorry, this script requires 'anchor' to be installed in your $PATH"
);
shell.exit(1);
}
fs.rmSync("idl", { recursive: true });
fs.mkdirSync("idl", { recursive: true });
execSync(
"anchor idl fetch -o ./idl/mainnet.json SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f --provider.cluster mainnet"
);
execSync(
"anchor idl fetch -o ./idl/devnet.json SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f --provider.cluster devnet"
);
if (isDev) {
execSync(
"rm -rf ./src/generated && npx anchor-client-gen --program-id SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f ../../../switchboard-core/switchboard_v2/target/idl/switchboard_v2.json ./src/generated"
);
} else {
execSync(
"rm -rf ./src/generated && npx anchor-client-gen --program-id SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f ./idl/mainnet.json ./src/generated"
);
}
fs.writeFileSync(
"./src/generated/index.ts",
[
"export * from './accounts/index.js';",
"export * from './errors/index.js';",
"export * from './instructions/index.js';",
"export * from './types/index.js';",
].join("\n")
);
// loop through directory and run regex replaces
for await (const file of [
...getAllFiles("./src/generated/accounts"),
...getAllFiles("./src/generated/errors"),
...getAllFiles("./src/generated/instructions"),
...getAllFiles("./src/generated/types"),
]) {
if (file.includes("index.ts")) {
continue;
}
const fileString = fs.readFileSync(file, "utf-8");
fs.writeFileSync(
file,
`import { SwitchboardProgram } from "../../SwitchboardProgram.js"\n${fileString}`
);
console.log(file);
// replace BN import
shell.sed(
"-i",
'import BN from "bn.js"',
'import { BN } from "@switchboard-xyz/common"',
file
);
// update types import
shell.sed(
"-i",
'import * as types from "../types"',
'import * as types from "../types/index.js"',
file
);
// replace borsh import
shell.sed("-i", "@project-serum", "@coral-xyz", file);
// remove PROGRAM_ID import, we will use SwitchboardProgram instead
shell.sed("-i", 'import { PROGRAM_ID } from "../programId"', "", file);
// replace PROGRAM_ID with program.programId
shell.sed("-i", "PROGRAM_ID", "program.programId", file);
// replace Connection with SwitchboardProgram
shell.sed("-i", "c: Connection,", "program: SwitchboardProgram,", file);
// replace c.getAccountInfo with the SwitchboardProgram connection
shell.sed(
"-i",
"c.getAccountInfo",
"program.connection.getAccountInfo",
file
);
// replace c.getMultipleAccountsInfo with the SwitchboardProgram connection
shell.sed(
"-i",
"c.getMultipleAccountsInfo",
"program.connection.getMultipleAccountsInfo",
file
);
// add program as first arguement to instructions
if (file.includes("/instructions/")) {
shell.sed("-i", "args:", "program: SwitchboardProgram, args:", file);
}
}
execSync("npx prettier ./src/generated --write");
// reset files
for (const file of ignoreFiles) {
execSync(`git restore ${file}`);
}
}
main()
.then(() => {
// console.log("Executed successfully");
})
.catch((err) => {
console.error(err);
});