2021-01-02 22:40:17 -08:00
|
|
|
import camelCase from "camelcase";
|
2021-05-23 13:57:55 -07:00
|
|
|
import * as toml from "toml";
|
2021-01-04 23:59:52 -08:00
|
|
|
import { PublicKey } from "@solana/web3.js";
|
|
|
|
import { Program } from "./program";
|
2021-05-23 17:06:39 -07:00
|
|
|
import { Idl } from "./idl";
|
2021-06-28 13:31:41 -07:00
|
|
|
import { isBrowser } from "./utils/common";
|
2021-01-02 22:40:17 -08:00
|
|
|
|
|
|
|
let _populatedWorkspace = false;
|
|
|
|
|
2021-05-10 13:12:20 -07:00
|
|
|
/**
|
|
|
|
* The `workspace` namespace provides a convenience API to automatically
|
|
|
|
* search for and deserialize [[Program]] objects defined by compiled IDLs
|
|
|
|
* in an Anchor workspace.
|
|
|
|
*
|
|
|
|
* This API is for Node only.
|
|
|
|
*/
|
|
|
|
const workspace = new Proxy({} as any, {
|
2021-01-04 23:59:52 -08:00
|
|
|
get(workspaceCache: { [key: string]: Program }, programName: string) {
|
2021-06-28 13:31:41 -07:00
|
|
|
if (isBrowser) {
|
2021-11-17 14:58:26 -08:00
|
|
|
throw new Error("Workspaces aren't available in the browser");
|
2021-01-04 23:59:52 -08:00
|
|
|
}
|
|
|
|
|
2021-06-28 13:31:41 -07:00
|
|
|
const fs = require("fs");
|
|
|
|
const process = require("process");
|
|
|
|
|
2021-01-04 23:59:52 -08:00
|
|
|
if (!_populatedWorkspace) {
|
|
|
|
const path = require("path");
|
|
|
|
|
|
|
|
let projectRoot = process.cwd();
|
|
|
|
while (!fs.existsSync(path.join(projectRoot, "Anchor.toml"))) {
|
|
|
|
const parentDir = path.dirname(projectRoot);
|
|
|
|
if (parentDir === projectRoot) {
|
|
|
|
projectRoot = undefined;
|
|
|
|
}
|
|
|
|
projectRoot = parentDir;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (projectRoot === undefined) {
|
2021-05-08 21:31:55 -07:00
|
|
|
throw new Error("Could not find workspace root.");
|
2021-01-02 22:40:17 -08:00
|
|
|
}
|
|
|
|
|
2021-06-17 22:20:40 -07:00
|
|
|
const idlFolder = `${projectRoot}/target/idl`;
|
|
|
|
if (!fs.existsSync(idlFolder)) {
|
2021-07-17 17:56:42 -07:00
|
|
|
throw new Error(
|
|
|
|
`${idlFolder} doesn't exist. Did you use "anchor build"?`
|
|
|
|
);
|
2021-06-17 22:20:40 -07:00
|
|
|
}
|
2021-05-23 17:06:39 -07:00
|
|
|
|
2021-06-17 22:20:40 -07:00
|
|
|
const idlMap = new Map<string, Idl>();
|
2021-07-17 17:56:42 -07:00
|
|
|
fs.readdirSync(idlFolder).forEach((file) => {
|
2021-06-17 22:20:40 -07:00
|
|
|
const filePath = `${idlFolder}/${file}`;
|
|
|
|
const idlStr = fs.readFileSync(filePath);
|
|
|
|
const idl = JSON.parse(idlStr);
|
|
|
|
idlMap.set(idl.name, idl);
|
2021-07-17 17:56:42 -07:00
|
|
|
const name = camelCase(idl.name, { pascalCase: true });
|
2021-06-17 22:20:40 -07:00
|
|
|
if (idl.metadata && idl.metadata.address) {
|
|
|
|
workspaceCache[name] = new Program(
|
|
|
|
idl,
|
|
|
|
new PublicKey(idl.metadata.address)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
});
|
2021-01-02 22:40:17 -08:00
|
|
|
|
2021-05-23 13:57:55 -07:00
|
|
|
// Override the workspace programs if the user put them in the config.
|
|
|
|
const anchorToml = toml.parse(
|
|
|
|
fs.readFileSync(path.join(projectRoot, "Anchor.toml"), "utf-8")
|
|
|
|
);
|
|
|
|
const clusterId = anchorToml.provider.cluster;
|
2021-08-08 02:11:48 -07:00
|
|
|
if (anchorToml.programs && anchorToml.programs[clusterId]) {
|
2021-05-23 17:06:39 -07:00
|
|
|
attachWorkspaceOverride(
|
|
|
|
workspaceCache,
|
2021-08-08 02:11:48 -07:00
|
|
|
anchorToml.programs[clusterId],
|
2021-05-23 17:06:39 -07:00
|
|
|
idlMap
|
|
|
|
);
|
2021-05-23 13:57:55 -07:00
|
|
|
}
|
|
|
|
|
2021-01-04 23:59:52 -08:00
|
|
|
_populatedWorkspace = true;
|
|
|
|
}
|
2021-01-02 22:40:17 -08:00
|
|
|
|
2021-01-04 23:59:52 -08:00
|
|
|
return workspaceCache[programName];
|
|
|
|
},
|
|
|
|
});
|
2021-05-10 13:12:20 -07:00
|
|
|
|
2021-05-23 13:57:55 -07:00
|
|
|
function attachWorkspaceOverride(
|
|
|
|
workspaceCache: { [key: string]: Program },
|
2021-06-27 13:17:05 -07:00
|
|
|
overrideConfig: { [key: string]: string | { address: string; idl?: string } },
|
2021-05-23 17:06:39 -07:00
|
|
|
idlMap: Map<string, Idl>
|
2021-05-23 13:57:55 -07:00
|
|
|
) {
|
|
|
|
Object.keys(overrideConfig).forEach((programName) => {
|
|
|
|
const wsProgramName = camelCase(programName, { pascalCase: true });
|
2021-06-27 13:17:05 -07:00
|
|
|
const entry = overrideConfig[programName];
|
|
|
|
const overrideAddress = new PublicKey(
|
|
|
|
typeof entry === "string" ? entry : entry.address
|
2021-05-23 13:57:55 -07:00
|
|
|
);
|
2021-06-27 13:17:05 -07:00
|
|
|
let idl = idlMap.get(programName);
|
|
|
|
if (typeof entry !== "string" && entry.idl) {
|
|
|
|
idl = JSON.parse(require("fs").readFileSync(entry.idl, "utf-8"));
|
|
|
|
}
|
2021-09-16 13:42:11 -07:00
|
|
|
if (!idl) {
|
|
|
|
throw new Error(`Error loading workspace IDL for ${programName}`);
|
|
|
|
}
|
2021-06-27 13:17:05 -07:00
|
|
|
workspaceCache[wsProgramName] = new Program(idl, overrideAddress);
|
2021-05-23 13:57:55 -07:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-05-10 13:12:20 -07:00
|
|
|
export default workspace;
|