All files require_check.ts

100% Statements 57/57
100% Branches 13/13
100% Functions 7/7
100% Lines 50/50

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 771x 1x 1x 1x 1x 1x           1x 1x 4x 4x 8x 8x       8x 8x   1x 1x         1x 7x   1x 7x   1x 14x 14x 14x 28x 14x 28x       14x 14x 14x 2x   12x 12x 8x 2x   6x 6x 12x 12x 4x   1x 8x   8x 1x   14x 1x 1x   7x 7x     1x  
import * as os from 'os';
import * as path from 'path';
import * as crypto from 'crypto';
import * as fs from 'fs';
import * as childProcess from 'child_process';
import * as util from 'util';
 
/** creates a temp directory where inits npm and installs provided local module
 * via npm install <local-module>, then evaluates "require(<module-name>)" from
 * the temp directory using node, ensures that package is can be required
 * reliably, dependencies are listed in npm, and transpilation has occurred. */
export class RequireCheck {
  static async rmdir(location: string) {
    const entries = await fs.promises.readdir(location, {withFileTypes: true});
    const promises = entries.map(entry => {
      const fullLocation = path.join(location, entry.name);
      return entry.isDirectory()
        ? RequireCheck.rmdir(fullLocation)
        : fs.promises.unlink(fullLocation);
    });
    await Promise.all(promises);
    await fs.promises.rmdir(location);
  }
  static exec = util.promisify(childProcess.exec);
  static template = {
    name: 'require-check-template',
    version: '1.0.0',
    description: 'This is a temporary package.json to test',
  };
  static async npmInstall(install: string, cwd: string) {
    return await RequireCheck.exec(`npm install ${install}`, {cwd});
  }
  static async requireModule(pkg: {name: string}, cwd: string) {
    return await RequireCheck.exec(`node -e "require('${pkg.name}')"`, {cwd});
  }
  static async check(modLocation: string) {
    const dir = os.tmpdir();
    const id = crypto.randomBytes(20).toString('hex');
    const destLocation = path.join(dir, 'require-check', id);
    await fs.promises.mkdir(destLocation, {recursive: true});
    const destPkg = path.join(destLocation, 'package.json');
    await fs.promises.writeFile(
      destPkg,
      JSON.stringify(RequireCheck.template, null, 2)
    );
    modLocation = path.resolve(modLocation);
    const modStat = await fs.promises.lstat(modLocation);
    if (!modStat.isDirectory()) {
      throw new Error('module path is not a directory');
    }
    const pkgLocation = path.join(modLocation, 'package.json');
    const pkgStat = await fs.promises.lstat(pkgLocation);
    if (!pkgStat.isFile()) {
      throw new Error('package.json is not present in module');
    }
    const pkgRaw = await fs.promises.readFile(pkgLocation, 'utf-8');
    const pkg = JSON.parse(pkgRaw);
    await RequireCheck.npmInstall(modLocation, destLocation);
    await RequireCheck.requireModule(pkg, destLocation);
    await RequireCheck.rmdir(destLocation);
  }
  static async cli(process: NodeJS.Process) {
    const modLocation = process.argv.slice(2)[0];
    try {
      if (typeof modLocation !== 'string') {
        throw new Error('invalid module location');
      }
      await RequireCheck.check(modLocation);
      process.stdout.write('success, module passed required check\n');
      process.exit(0);
    } catch (e) {
      process.stderr.write(`${e.message}\n`);
      process.exit(1);
    }
  }
}