UNPKG

@truffle/compile-solidity

Version:
211 lines (186 loc) 7.17 kB
import debugModule from "debug"; const debug = debugModule("compile"); import findContracts from "@truffle/contract-sources"; import Config from "@truffle/config"; import { Profiler } from "./profiler"; import { CompilerSupplier } from "./compilerSupplier"; import { run } from "./run"; import { normalizeOptions } from "./normalizeOptions"; import { compileWithPragmaAnalysis } from "./compileWithPragmaAnalysis"; import { reportSources } from "./reportSources"; import { Compilations } from "@truffle/compile-common"; import type { Compilation } from "@truffle/compile-common"; import partition from "lodash/partition"; import fs from "fs-extra"; import type { SourcesWithDependenciesArgs, SourcesArgs } from "./types"; const expect = require("@truffle/expect"); export { CompilerSupplier } from "./compilerSupplier"; export * as Shims from "./shims"; export { compileWithPragmaAnalysis } from "./compileWithPragmaAnalysis"; export { Profiler } from "./profiler"; export { Cache } from "./compilerSupplier/Cache"; export * as LoadingStrategies from "./compilerSupplier/loadingStrategies"; export { shouldIncludePath } from "./profiler/shouldIncludePath"; export { run } from "./run"; export { Parser } from "./parser"; export * as RangeUtils from "./compilerSupplier/rangeUtils"; async function compileYulPaths(yulPaths: string[], options: Config) { let yulCompilations: Compilation[] = []; for (const path of yulPaths) { const yulOptions = options.with({ compilationTargets: [path] }); //load up Yul sources, since they weren't loaded up earlier //(we'll just use FS for this rather than going through the resolver, //for simplicity, since there are no imports to worry about) const yulSource = fs.readFileSync(path, { encoding: "utf8" }); debug("Compiling Yul"); const compilation = await run({ [path]: yulSource }, yulOptions, { language: "Yul" }); debug("Yul compiled successfully"); if (compilation && compilation.contracts.length > 0) { yulCompilations.push(compilation); } } if (yulPaths.length > 0 && !options.quiet) { //replacement for individual Yul warnings options.logger.log( "> Warning: Yul is still experimental. Avoid using it in live deployments." ); } return yulCompilations; } export const Compile = { // this takes an object with keys being the name and values being source // material as well as an options object // NOTE: this function does *not* transform the source path prefix to // "project:/" before passing to the compiler! async sources({ sources, options }: SourcesArgs) { options = Config.default().merge(options); options = normalizeOptions(options); //note: "solidity" here includes JSON as well! const [yulNames, solidityNames] = partition(Object.keys(sources), name => name.endsWith(".yul") ); const soliditySources = Object.assign( {}, ...solidityNames.map(name => ({ [name]: sources[name] })) ); let solidityCompilations: Compilation[] = []; let yulCompilations: Compilation[] = []; if (solidityNames.length > 0) { debug("Compiling Solidity (specified sources)"); const compilation = await run(soliditySources, options, { noTransform: true }); debug("Compiled Solidity"); if (compilation && compilation.contracts.length > 0) { solidityCompilations.push(compilation); } } for (const name of yulNames) { debug("Compiling Yul (specified sources)"); const compilation = await run({ [name]: sources[name] }, options, { language: "Yul", noTransform: true }); debug("Compiled Yul"); if (compilation !== null) { yulCompilations.push(compilation); } } const compilations = [...solidityCompilations, ...yulCompilations]; return Compilations.promoteCompileResult({ compilations }); }, async all(options: Config) { const paths = [ ...new Set([ ...(await findContracts(options.contracts_directory)), ...(options.files || []) ]) ]; return await Compile.sourcesWithDependencies({ paths, options }); }, async necessary(options: Config) { options.logger = options.logger || console; const paths = await Profiler.updated(options); return await Compile.sourcesWithDependencies({ paths, options }); }, async sourcesWithDependencies({ paths, options }: SourcesWithDependenciesArgs) { if (options.compilers.solc.version === "pragma") { return this.sourcesWithPragmaAnalysis({ paths, options }); } options.logger = options.logger || console; options.contracts_directory = options.contracts_directory || process.cwd(); debug("paths: %O", paths); expect.options(options, [ "working_directory", "contracts_directory", "resolver" ]); options = Config.default().merge(options); options = normalizeOptions(options); const supplier = new CompilerSupplier({ events: options.events, solcConfig: options.compilers.solc }); const { solc } = await supplier.load(); //note: solidityPaths here still includes JSON as well! const [yulPaths, solidityPaths] = partition(paths, path => path.endsWith(".yul") ); debug("invoking profiler"); //only invoke profiler on Solidity, not Yul const { allSources, compilationTargets } = await Profiler.requiredSources( options.with({ paths: solidityPaths, base_path: options.contracts_directory, resolver: options.resolver, compiler: { name: "solc", version: solc.version() } }), solc ); debug("compilationTargets: %O", compilationTargets); // we can exit if there are no Solidity/Yul files to compile since // it indicates that we only have Vyper-related JSON const solidityTargets = compilationTargets.filter(fileName => fileName.endsWith(".sol") ); if (solidityTargets.length === 0 && yulPaths.length === 0) { return Compilations.emptyWorkflowCompileResult(); } reportSources({ paths: [...compilationTargets, ...yulPaths], options }); let solidityCompilations: Compilation[] = []; // only call run if there are sources to run on! if (Object.keys(allSources).length > 0) { const solidityOptions = options.with({ compilationTargets }); debug("Compiling Solidity"); const compilation = await run(allSources, solidityOptions, { solc }); debug("Solidity compiled successfully"); if (compilation && compilation.contracts.length > 0) { solidityCompilations.push(compilation); } } const yulCompilations = await compileYulPaths(yulPaths, options); const compilations = [...solidityCompilations, ...yulCompilations]; return Compilations.promoteCompileResult({ compilations }); }, async sourcesWithPragmaAnalysis({ paths, options }) { const compilationResult = await compileWithPragmaAnalysis({ paths, options }); return Compilations.promoteCompileResult(compilationResult); } };