All files / check-installed/lib checkEngines.js

100% Statements 27/27
100% Branches 16/16
100% Functions 7/7
100% Lines 27/27

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 77 78 791x 1x 1x               16x   16x 16x   16x 14x     16x 16x 2x   14x                         16x   16x 6x     10x                   10x     10x   16x     7x 1x     7x 1x 2x       7x 2x       1x      
const { spawn } = require('child_process')
const semver = require('semver')
const { OPTIONS } = require('./constants')
 
/**
 * Get the version of an engine
 * @param {string} name - The name of the engine to get version for
 * @returns {Promise<string>} - The version of the engine
 */
async function getEngineVersion (name) {
  const spawned = spawn(name, ['--version'], { shell: true })
 
  return new Promise((resolve) => {
    let result = ''
 
    spawned.stdout.on('data', (data) => {
      result += data.toString()
    })
 
    spawned.on('close', (code) => {
      if (code !== 0) {
        resolve('none')
      } else {
        resolve(result.trim())
      }
    })
  })
}
 
/**
 * Checks that the given engine is installed and satisfies version (throws if not)
 * @param {string} name - The name of the engine to check
 * @param {string} version - The version to check against
 * @returns {Promise<[string, string, string]>} - The [name, version, installed] installed and checked successfully
 */
async function checkEngineVersion (name, version) {
  const installed = await getEngineVersion(name)
 
  if (!semver.satisfies(installed, version)) {
    throw new Error(`check-installed engine failed for ${name}: installed ${installed}, expected ${version}`)
  }
 
  return [name, version, installed]
}
 
/**
 * Checks engines in `package.json` are installed
 * @param {object} json - The `package.json` JSON object
 * @param {Partial<typeof import('./constants').OPTIONS>} options - Options for the CLI
 * @returns {Promise<void>} - Resolves when all engines are checked (throws on check fail)
 */
async function checkEngines (json = {}, options = {}) {
  const { showSuccess, showEngines } = { ...OPTIONS, ...options }
 
  // Check engines
  const engines = await Promise.all(
    Object.entries(json.engines || {})
      .map(([name, version]) => checkEngineVersion(name, version))
  )
 
  if (showSuccess) {
    console.log('check-installed engines successful')
  }
 
  if (showEngines) {
    for (const [name, version, installed] of engines) {
      console.log(`${name}: ${installed} (${version})`)
    }
  }
 
  if (showSuccess || showEngines) {
    console.log('')
  }
}
 
module.exports = {
  checkEngines
}