trufflesuite/truffle

View on GitHub
packages/from-hardhat/src/ask-hardhat.ts

Summary

Maintainability
A
0 mins
Test Coverage
import { spawn } from "child_process";

import findUp from "find-up";

import { validHardhatConfigFilenames } from "./constants";
import { EnvironmentOptions, withDefaultEnvironmentOptions } from "./options";

/**
 * Returns a Promise to a boolean that is true if and only if
 * the detected or specified environment is part of a Hardhat project.
 *
 * (i.e., if the working directory or any of its parents has a Hardhat config)
 */
export const checkHardhat = async (
  options?: EnvironmentOptions
): Promise<boolean> => {
  const { workingDirectory } = withDefaultEnvironmentOptions(options);

  // search recursively up for a hardhat config
  const hardhatConfigPath = await findUp(validHardhatConfigFilenames, {
    cwd: workingDirectory
  });

  return !!hardhatConfigPath;
};

/**
 * Reads version information via `npx hardhat --version`
 */
export const askHardhatVersion = async (
  options?: EnvironmentOptions
): Promise<string> =>
  new Promise((accept, reject) => {
    const { workingDirectory } = withDefaultEnvironmentOptions(options);

    const hardhat = spawn(`npx`, ["hardhat", "--version"], {
      stdio: ["pipe", "pipe", "inherit"],
      cwd: workingDirectory,
      shell: true
    });

    let output = "";
    hardhat.stdout.on("data", data => {
      output = `${output}${data}`;
    });

    hardhat.once("close", code => {
      if (code !== 0) {
        return reject(new Error(`Hardhat exited with non-zero code ${code}`));
      }

      return accept(output);
    });
  });

export interface AskHardhatConsoleOptions {
  // turn off json stringify/parse
  raw?: boolean;
}

export const askHardhatConsole = async (
  expression: string,
  {
    raw = false,
    ...options
  }: AskHardhatConsoleOptions & EnvironmentOptions = {}
): Promise<string | unknown> =>
  new Promise((accept, reject) => {
    const { workingDirectory } = withDefaultEnvironmentOptions(options);

    // Latin-1 Supplemental block control codes
    const sos = String.fromCodePoint(0x0098); // start of string
    const st = String.fromCodePoint(0x009c); // string terminator
    const prefix = `${sos}truffle-start${st}`;
    const suffix = `${sos}truffle-end${st}`;

    // note the hardhat console instance is spawned with --no-compile which causes it to skip the initial (default) compilation step
    const hardhat = spawn(`npx`, ["hardhat", "console", "--no-compile"], {
      stdio: ["pipe", "pipe", "inherit"],
      cwd: workingDirectory,
      shell: true
    });

    // we'll capture the stdout
    let output = "";
    hardhat.stdout.on("data", data => {
      output = `${output}${data}`;
    });

    // setup close event before writing to stdin because we're sending eof
    hardhat.once("close", code => {
      if (code !== 0) {
        return reject(new Error(`Hardhat exited with non-zero code ${code}`));
      }

      const data = output.slice(
        output.indexOf(prefix) + prefix.length,
        output.indexOf(suffix)
      );

      if (raw) {
        return accept(data);
      }

      try {
        const result = JSON.parse(data);

        return accept(result);
      } catch (error) {
        return reject(error);
      }
    });

    // write to stdin to ask for requested data. this does a few things:
    // - wrap the expression into something that resolves as a Promise.
    //   this ensures that we can handle raw synchronous expressions as well
    //   as Promise-returning expressions.
    // - write the resolved value to the console, using the prefix/suffix
    //   sentinels to ensure Truffle knows what stdout comes from this process,
    //   vs. whatever stdout Hardhat may produce on its own.
    // - unless `raw` is turned on, stringify the resolved value as JSON.
    hardhat.stdin.write(`
      Promise.resolve(${expression})
        .then(${
          raw
            ? `(resolved) => console.log(
                \`${prefix}$\{resolved}${suffix}\`
              )`
            : `(resolved) => console.log(
                \`${prefix}$\{JSON.stringify(resolved)}${suffix}\`
              )`
        })
    `);
    hardhat.stdin.end();
  });