UNPKG

@nomiclabs/buidler

Version:

Buidler is an extensible developer tool that helps smart contract developers increase productivity by reliably bringing together the tools they want.

90 lines (73 loc) 2.83 kB
import { internalTask, task } from "../internal/core/config/config-env"; import { BuidlerError } from "../internal/core/errors"; import { ERRORS } from "../internal/core/errors-list"; import { DependencyGraph } from "../internal/solidity/dependencyGraph"; import { ResolvedFile, ResolvedFilesMap } from "../internal/solidity/resolver"; import { getPackageJson } from "../internal/util/packageInfo"; import { TASK_COMPILE_GET_DEPENDENCY_GRAPH, TASK_FLATTEN, TASK_FLATTEN_GET_FLATTENED_SOURCE, } from "./task-names"; function getSortedFiles(dependenciesGraph: DependencyGraph) { const tsort = require("tsort"); const graph = tsort(); const filesMap: ResolvedFilesMap = {}; const resolvedFiles = dependenciesGraph.getResolvedFiles(); resolvedFiles.forEach((f) => (filesMap[f.globalName] = f)); for (const [from, deps] of dependenciesGraph.dependenciesPerFile.entries()) { for (const to of deps) { graph.add(to.globalName, from.globalName); } } try { const topologicalSortedNames: string[] = graph.sort(); // If an entry has no dependency it won't be included in the graph, so we // add them and then dedup the array const withEntries = topologicalSortedNames.concat( resolvedFiles.map((f) => f.globalName) ); const sortedNames = [...new Set(withEntries)]; return sortedNames.map((n) => filesMap[n]); } catch (error) { if (error.toString().includes("Error: There is a cycle in the graph.")) { throw new BuidlerError(ERRORS.BUILTIN_TASKS.FLATTEN_CYCLE, error); } // tslint:disable-next-line only-buidler-error throw error; } } function getFileWithoutImports(resolvedFile: ResolvedFile) { const IMPORT_SOLIDITY_REGEX = /^\s*import(\s+)[\s\S]*?;\s*$/gm; return resolvedFile.content.replace(IMPORT_SOLIDITY_REGEX, "").trim(); } export default function () { internalTask( TASK_FLATTEN_GET_FLATTENED_SOURCE, "Returns all contracts and their dependencies flattened", async (_, { run }) => { let flattened = ""; const graph: DependencyGraph = await run( TASK_COMPILE_GET_DEPENDENCY_GRAPH ); if (graph.getResolvedFiles().length === 0) { return flattened; } const packageJson = await getPackageJson(); flattened += `// Sources flattened with buidler v${packageJson.version} https://buidler.dev`; const sortedFiles = getSortedFiles(graph); for (const file of sortedFiles) { flattened += `\n\n// File ${file.getVersionedName()}\n`; flattened += `\n${getFileWithoutImports(file)}\n`; } return flattened.trim(); } ); task( TASK_FLATTEN, "Flattens and prints all contracts and their dependencies", async (_, { run }) => { console.log(await run(TASK_FLATTEN_GET_FLATTENED_SOURCE)); } ); }