UNPKG

@simbachain/web3-suites

Version:

common code for web3 suite plugins. Code in this repo can be used for truffle or hardhat, but is designed to be applicable to future web3 suite plugins as well.

317 lines 13.3 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SourceCodeComparer = void 0; const chalk_1 = __importDefault(require("chalk")); const lib_1 = require("../lib"); /** * this class is used to compare source code in simba.json to our build artifacts, * which helps us determine which contracts should/can be exported */ class SourceCodeComparer { /** * grabs source code for all compiled contracts from local build artifacts * @returns */ async getAndSetSourceCodeFromArtifacts() { lib_1.SimbaConfig.log.debug(`:: ENTER :`); const buildDir = lib_1.SimbaConfig.buildDirectory; let files = []; let sourceCodeMap = {}; const HARDHAT = "hardhat"; const TRUFFLE = "truffle"; try { files = await (0, lib_1.walkDirForContracts)(buildDir, '.json'); } catch (e) { const err = e; if (err.code === 'ENOENT') { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: Simba was not able to find any build artifacts.\nDid you forget to compile?\n`)}`); } lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: ${JSON.stringify(err)}`)}`); this.sourceCodeFromArtifacts = sourceCodeMap; return sourceCodeMap; } const web3Suite = (0, lib_1.discoverAndSetWeb3Suite)(); if (!web3Suite) { lib_1.SimbaConfig.log.error(lib_1.web3SuiteErrorMessage); return sourceCodeMap; } switch (web3Suite) { case HARDHAT: { for (const file of files) { if (file.endsWith('Migrations.json') || file.endsWith('dbg.json')) { continue; } const buf = await (0, lib_1.promisifiedReadFile)(file, { flag: 'r' }); if (!(buf instanceof Buffer)) { continue; } const parsed = JSON.parse(buf.toString()); const contractName = parsed.contractName; const contractSourceName = parsed.sourceName; const astAndOtherInfo = await (0, lib_1.getASTAndOtherInfo)(contractName, contractSourceName); const sourceCode = astAndOtherInfo.source; sourceCodeMap[contractName] = sourceCode; } break; } case TRUFFLE: { for (const file of files) { if (file.endsWith('Migrations.json')) { continue; } const buf = await (0, lib_1.promisifiedReadFile)(file, { flag: 'r' }); if (!(buf instanceof Buffer)) { continue; } const parsed = JSON.parse(buf.toString()); const contractName = parsed.contractName; const sourceCode = parsed.source; sourceCodeMap[contractName] = sourceCode; } break; } default: { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`simba: ${web3Suite} is not a supported web3Suite`)}`); break; } } lib_1.SimbaConfig.log.debug(`:: EXIT : sourceCodeMap from Artifacts : ${JSON.stringify(sourceCodeMap)}`); this.sourceCodeFromArtifacts = sourceCodeMap; return sourceCodeMap; } /** * grabs source code from simba.json * contracts_info.<contract_name> exists after a file has been exported * @returns */ getAndSetSourceCodeFromSimbaJson() { lib_1.SimbaConfig.log.debug(`:: ENTER :`); const contractsInfo = lib_1.SimbaConfig.ProjectConfigStore.get("contracts_info"); let sourceCodeMap = {}; if (!contractsInfo) { lib_1.SimbaConfig.log.debug(`${chalk_1.default.cyanBright(`simba: no contracts_info found in simba.json`)}`); this.sourceCodeFromSimbaJson = sourceCodeMap; return sourceCodeMap; } for (let contractName in contractsInfo) { const sourceCode = contractsInfo[contractName].source_code; sourceCodeMap[contractName] = sourceCode; } lib_1.SimbaConfig.log.debug(`:: EXIT : sourceCodeMap from simba.json : ${JSON.stringify(sourceCodeMap)}`); this.sourceCodeFromSimbaJson = sourceCodeMap; return sourceCodeMap; } /** * checks if source code for contractName exists in simba.json * @param contractName * @returns */ sourceCodeExistsInSimbaJson(contractName) { lib_1.SimbaConfig.log.debug(`:: ENTER : contractName : ${contractName}`); this.initSimbaJsonSourceCode(); if (!this.sourceCodeFromSimbaJson) { this.getAndSetSourceCodeFromSimbaJson(); } if (Object.keys(this.sourceCodeFromSimbaJson).length === 0) { lib_1.SimbaConfig.log.debug(`:: EXIT : false`); return false; } if (this.sourceCodeFromSimbaJson[contractName]) { lib_1.SimbaConfig.log.debug(`:: EXIT : true`); return true; } else { lib_1.SimbaConfig.log.debug(`:: EXIT : false`); return false; } } /** * checks if source code for contractName exists in artifacts / build dir * @param contractName * @returns */ async sourceCodeExistsInArtifacts(contractName) { lib_1.SimbaConfig.log.debug(`:: ENTER : contractName : ${contractName}`); await this.initArtifactSourceCode(); if (Object.keys(this.sourceCodeFromArtifacts).length === 0) { lib_1.SimbaConfig.log.debug(`:: EXIT : false`); return false; } if (this.sourceCodeFromArtifacts[contractName]) { lib_1.SimbaConfig.log.debug(`:: EXIT : true`); return true; } else { lib_1.SimbaConfig.log.debug(`:: EXIT : false`); return false; } } /** * compares build artifacts and simba.json to see if contract is new or updated * @param contractName * @returns */ async sourceCodeHasChangedOrIsNew(contractName) { lib_1.SimbaConfig.log.debug(`:: ENTER : contractName : ${contractName}`); await this.initSourceCode(); if (!this.sourceCodeExistsInArtifacts(contractName)) { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`simba: source code for ${contractName} does not exist in your artifacts. Did you forget to compile your contracts?`)}`); lib_1.SimbaConfig.log.debug(`:: EXIT :`); return true; } if (!this.sourceCodeExistsInSimbaJson(contractName)) { lib_1.SimbaConfig.log.debug(`source code is new: returning true`); lib_1.SimbaConfig.log.debug(`:: EXIT :`); return true; } // existence of source code in both locations has been checked // now checking for sameness if (this.sourceCodeFromArtifacts[contractName] !== this.sourceCodeFromSimbaJson[contractName]) { lib_1.SimbaConfig.log.debug(`artifact source code and simba.json source code are different: returning true`); lib_1.SimbaConfig.log.debug(`:: EXIT :`); return true; } else { lib_1.SimbaConfig.log.debug(`source code in simba.json and artifacts match. returning false`); return false; } } /** * used to communicate to user the status of an attempted export * @param contractName * @returns */ async getStatusAndMessage(contractName) { lib_1.SimbaConfig.log.debug(`:: ENTER : contractName: ${contractName}`); if (!this.sourceCodeFromArtifacts || !this.sourceCodeFromSimbaJson) { await this.initSourceCode(); } if (!this.imports) { await this.getAndSetimports(); } const nonExportMessage = "No changes detected; not exported"; const attemptedExportMessage = "Error encountered with one or more contracts before export"; // const exportMessage = "Exported"; const isDependencyMessage = "Contract is a dependency; not exported"; let statusAndMessage; if (this.imports.includes(contractName)) { statusAndMessage = { newOrChanged: false, message: `${chalk_1.default.gray(`${isDependencyMessage}`)}` }; } else { if (!await this.sourceCodeHasChangedOrIsNew(contractName)) { statusAndMessage = { newOrChanged: false, message: `${chalk_1.default.gray(`${nonExportMessage}`)}`, }; } else { // by default, we set export message to error, and then // let the plugins handle updating the message to success statusAndMessage = { newOrChanged: true, message: `${chalk_1.default.redBright(`${attemptedExportMessage}`)}`, }; } } lib_1.SimbaConfig.log.debug(`:: EXIT : statusAndMessage : ${JSON.stringify(statusAndMessage)}`); return statusAndMessage; } /** * calls getStatusAndMessage for each attempted contract export, to communicate * statuses to user when attempting exports * @param choices * @returns */ async exportStatuses(choices) { const _exportStatuses = {}; await this.initSourceCode(); await this.getAndSetimports(); if (Array.isArray(choices)) { for (let i = 0; i < choices.length; i++) { const contractName = choices[i].title; const statusAndMessage = await this.getStatusAndMessage(contractName); _exportStatuses[contractName] = statusAndMessage; } lib_1.SimbaConfig.log.debug(`:: EXIT : _exportStatuses: ${JSON.stringify(_exportStatuses)}`); return _exportStatuses; } const contractName = choices; const statusAndMessage = await this.getStatusAndMessage(contractName); _exportStatuses[contractName] = statusAndMessage; lib_1.SimbaConfig.log.debug(`:: EXIT : _exportStatuses: ${JSON.stringify(_exportStatuses)}`); return _exportStatuses; } /** * sets simba.json and build artifact source code as property of this class */ async initSourceCode() { await this.initArtifactSourceCode(); this.initSimbaJsonSourceCode(); } /** * sets build artifact source code as property of this class */ async initArtifactSourceCode() { if (!this.sourceCodeFromArtifacts) { await this.getAndSetSourceCodeFromArtifacts(); } } /** * sets simba.json source code as property of this class */ initSimbaJsonSourceCode() { if (!this.sourceCodeFromSimbaJson) { this.getAndSetSourceCodeFromSimbaJson(); } } /** * this method is living in this class because it helps us determine * what to export or not. If an artifact has empty bytecode, * then it is an import (dependency), and we don't export it * @returns */ async getAndSetimports() { lib_1.SimbaConfig.log.debug(`:: ENTER :`); let files; const importedContracts = []; const buildDir = lib_1.SimbaConfig.buildDirectory; try { files = await (0, lib_1.walkDirForContracts)(buildDir, '.json'); } catch (e) { const err = e; if (err.code === 'ENOENT') { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : Simba was not able to find any build artifacts.\nDid you forget to compile?\n`)}`); } lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : ${JSON.stringify(err)}`)}`); return importedContracts; } for (const file of files) { if (file.endsWith('Migrations.json') || file.endsWith('dbg.json')) { continue; } const buf = await (0, lib_1.promisifiedReadFile)(file, { flag: 'r' }); if (!(buf instanceof Buffer)) { continue; } const parsed = JSON.parse(buf.toString()); const contractName = parsed.contractName; const byteCode = parsed.bytecode; if (byteCode === "0x") { importedContracts.push(contractName); } } lib_1.SimbaConfig.log.debug(`:: EXIT : importedContracts : ${JSON.stringify(importedContracts)}`); this.imports = importedContracts; return importedContracts; } } exports.SourceCodeComparer = SourceCodeComparer; //# sourceMappingURL=source_code_comparer.js.map