UNPKG

locklift

Version:

Node JS framework for working with Ever contracts. Inspired by Truffle and Hardhat. Helps you to build, test, run and maintain your smart contracts.

216 lines (215 loc) 9.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Builder = void 0; const child_process_1 = require("child_process"); const generators_1 = require("../../generators"); const ejs_1 = __importDefault(require("ejs")); const fs_1 = __importDefault(require("fs")); const path_1 = __importStar(require("path")); const underscore_1 = __importDefault(require("underscore")); const utils_1 = require("./utils"); const logger_1 = require("../../logger"); const preload_1 = __importDefault(require("semver/preload")); const utils_2 = require("../../utils"); const buildCache_1 = require("../../buildCache"); class Builder { config; compilerVersion; options; nameRegex = /======= (?<contract>.*) =======/g; docRegex = /(?<doc>^{(\s|.)*?^})/gm; constructor(config, options, compilerVersion) { this.config = config; this.compilerVersion = compilerVersion; if (preload_1.default.gte(compilerVersion, "0.72.0") && config.linkerPath) { logger_1.logger.printWarn("Linker is no longer used as of version 72+ and can be removed from the configuration"); } if (preload_1.default.eq(compilerVersion, "0.72.0")) { logger_1.logger.printWarn("0.72.0 compiler is considered unsafe and is not recommended. Use at your own risk!"); } this.options = options; } static create(config, options) { const matchedCompilerVersion = (0, child_process_1.execSync)(config.compilerPath + " --version") .toString() .trim() .match(/(?<=Version: |sold)(.*)(?=\+commit)/); if (!matchedCompilerVersion) { throw new Error("Cannot get compiler version"); } return new Builder(config, options, matchedCompilerVersion[0]); } async buildContracts() { const contractsTree = (0, utils_2.getContractsTree)(this.options.contracts); const { contractArtifacts, contractsToBuild: externalContracts } = await (0, utils_1.resolveExternalContracts)(this.config.externalContracts); const totalContracts = [...contractsTree.map(el => el.path), ...externalContracts]; const buildCache = new buildCache_1.BuildCache(totalContracts, this.options.force, this.options.build, this.config); const contractsToBuild = await buildCache.buildTree(); logger_1.logger.printInfo(`Found ${totalContracts.length} sources`); if (contractsToBuild.length > 0) { logger_1.logger.printInfo(`Found ${contractsToBuild.length} changes, compiling...`); try { await this.compileContracts(contractsToBuild); logger_1.logger.printInfo("Built"); buildCache.applyCurrentCache(); } catch (err) { if (err) { logger_1.logger.printError(err); } return false; } } else { logger_1.logger.printInfo("No changes found, skip compilation"); } if (contractArtifacts.length > 0) { contractArtifacts.forEach(artifact => fs_1.default.copyFileSync(artifact, (0, path_1.resolve)(this.options.build, path_1.default.basename(artifact)))); } if (this.config.externalContractsArtifacts) { (0, generators_1.copyExternalArtifacts)(this.config.externalContractsArtifacts, this.options.build); } (0, generators_1.typeGenerator)(this.options.build, ...(this.options.externalAbiFiles || [])); logger_1.logger.printInfo("factorySource generated"); return true; } compileContracts(contractsToBuild) { const contracts = contractsToBuild .map(el => ({ path: (0, path_1.resolve)(el) })) .map(el => ({ ...el, contractFileName: (0, utils_1.extractContractName)(el.path), })); if (this.config.mode === "solc") { logger_1.logger.printInfo("Compiling with solc"); return (0, utils_1.compileBySolC)({ contracts, compilerPath: this.config.compilerPath, compilerParams: this.config.compilerParams, compilerVersion: this.compilerVersion, linkerPath: this.config.linkerPath, disableIncludePath: this.options.disableIncludePath, linkerLibPath: this.config.linkerLibPath, buildFolder: this.options.build, }); } if (this.config.mode === "sold") { logger_1.logger.printInfo("Compiling with sold"); return (0, utils_1.compileBySolD)({ contracts, compilerPath: this.config.compilerPath, compilerParams: this.config.compilerParams, compilerVersion: this.compilerVersion, disableIncludePath: this.options.disableIncludePath, buildFolder: this.options.build, soldPath: this.config.soldPath, }); } } buildDocs() { const contractsTree = (0, utils_2.getContractsTree)(this.options.contracts); try { logger_1.logger.printInfo(`Found ${contractsTree.length} sources`); let docs = []; contractsTree.map(({ path }) => { logger_1.logger.printInfo(`Building ${path}`); const output = (0, utils_1.execSyncWrapper)( //@ts-ignore `cd ${this.options.build} && ${this.config.compilerPath} ./../${path} --${this.options.mode}`); logger_1.logger.printInfo(`Compiled ${path}`); docs = [...docs, ...this.parseDocs(output.toString())]; }); // Filter duplicates by (path, name) docs = docs.reduce((acc, doc) => { if (acc.find(({ path, name }) => path === doc.path && name === doc.name)) { return acc; } return [...acc, doc]; }, []); // Sort docs by name (A-Z) docs = docs.sort((a, b) => (a.name < b.name ? -1 : 1)); // Save docs in markdown format const render = ejs_1.default.render(fs_1.default.readFileSync((0, path_1.resolve)(__dirname, "./../templates/index.ejs")).toString(), { docs, }, { rmWhitespace: true, }); //@ts-ignore fs_1.default.writeFileSync( //@ts-ignore (0, path_1.resolve)(process.cwd(), this.options.docs, "index.md"), render); logger_1.logger.printInfo("Docs generated successfully!"); } catch (e) { logger_1.logger.printError(e); return false; } return true; } parseDocs(output) { const contracts = [...output.matchAll(this.nameRegex)] .map(m => m.groups.contract) // For the target contracts compiler returns relative path // and for dependency contracts paths are absolute // Make them all absolute .map(c => (0, path_1.resolve)(process.cwd(), this.options.build, c)); const docs = [...output.matchAll(this.docRegex)].map(m => //@ts-ignore JSON.parse(m.groups?.doc)); return underscore_1.default.zip(contracts, docs).reduce((acc, [contract, doc]) => { const [path, name] = contract.split(":"); // Check name matches the "include" pattern and contract is located in the "contracts" dir if ( //@ts-ignore name.match(new RegExp(this.options.include)) !== null && path.startsWith(`${process.cwd()}/${this.options.contracts}`)) { return [ ...acc, { path: path.replace(`${process.cwd()}/`, ""), name, doc, }, ]; } return acc; }, []); } } exports.Builder = Builder;