hardhat-scilla-plugin
Version:
Hardhat TypeScript plugin for scilla testing
124 lines (104 loc) • 3.42 kB
text/typescript
import clc from "cli-color";
import { createHash } from "crypto";
import fs from "fs";
import { glob } from "glob";
import path, { dirname } from "path";
import {
ContractName,
ParsedContract,
parseScilla,
parseScillaLibrary,
} from "./ScillaParser";
// For some reason, hardhat deletes json files in artifacts, so it couldn't be scilla.json
const CONTRACTS_INFO_CACHE_FILE = "artifacts/scilla.cache";
export interface ContractInfo {
hash: string;
path: string;
parsedContract: ParsedContract;
}
type ContractPath = string;
type ContractMapByName = Record<ContractName, ContractInfo>;
export type ScillaContracts = ContractMapByName;
type ContractMapByPath = Record<ContractPath, ContractInfo>;
export const updateContractsInfo = async () => {
let contractsInfo: ContractMapByName = {};
const files = glob.sync("contracts/**/*(*.scilla|*.scillib)");
if (files.length === 0) {
console.log(
clc.yellowBright("No scilla contracts were found in contracts directory.")
);
return;
}
contractsInfo = loadContractsInfo();
let somethingChanged = false;
for (const file of files) {
if (
file in contractsInfo &&
contractsInfo[file].hash === getFileHash(file)
) {
continue;
}
// Either the file is new or has been changed
const contract = await parseScillaFile(file);
console.log(`Parsing ${file}...`);
if (contract) {
somethingChanged = true;
contractsInfo[file] = contract;
} else {
console.log(clc.redBright(" Failed!"));
}
}
if (somethingChanged) {
console.log("Cache updated.");
saveContractsInfo(contractsInfo);
} else {
console.log("Nothing changed since last compile.");
}
};
export const loadScillaContractsInfo = (): ContractMapByName => {
const contractsInfo = loadContractsInfo();
return convertToMapByName(contractsInfo);
};
const convertToMapByName = (
contracts: ContractMapByPath
): ContractMapByName => {
const contractsByName: ContractMapByName = {};
for (const key in contracts) {
const elem = contracts[key];
const contractName: ContractName = elem.parsedContract.name;
contractsByName[contractName] = elem;
}
return contractsByName;
};
const loadContractsInfo = (): ContractMapByPath => {
if (!fs.existsSync(CONTRACTS_INFO_CACHE_FILE)) {
console.log("Cache file doesn't exist, creating a new one");
return {};
}
const contents = fs.readFileSync(CONTRACTS_INFO_CACHE_FILE, "utf8");
return JSON.parse(contents);
};
const saveContractsInfo = (contracts: ContractMapByPath) => {
fs.mkdirSync(dirname(CONTRACTS_INFO_CACHE_FILE), { recursive: true });
fs.writeFileSync(CONTRACTS_INFO_CACHE_FILE, JSON.stringify(contracts));
};
export const getFileHash = (fileName: string): string => {
const contents = fs.readFileSync(fileName, "utf8");
const hashSum = createHash("md5");
hashSum.update(contents);
return hashSum.digest("hex");
};
const parseScillaFile = async (
fileName: string
): Promise<ContractInfo | null> => {
const contents = fs.readFileSync(fileName, "utf8");
const hashSum = createHash("md5");
hashSum.update(contents);
let parsedContract;
if (path.extname(fileName) === ".scillib") {
parsedContract = await parseScillaLibrary(fileName);
} else {
parsedContract = parseScilla(fileName);
}
return { hash: hashSum.digest("hex"), path: fileName, parsedContract };
};