All files / src/scripts hoist.js

50% Statements 28/56
50% Branches 5/10
57.14% Functions 4/7
50% Lines 28/56
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 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 1382x 2x 2x 2x 2x 2x   2x                                                                                                                   2x                           2x 3x 3x   3x   4x         4x             3x           2x 8x 4x     4x         4x   5x 5x 5x 2x       3x   3x           4x     2x        
const fs = require('fs-extra')
const promisify = require('util').promisify
const exec = promisify(require('child_process').exec)
const { getArg } = require('../args/getArg')
const writeJsonFile = require('../file/writeJsonFile')
const log = require('../log')
 
const hoistPackages = async ({ appLocation, covenantConfig }) => {
  log.info('interbit-hoist: Hoisting covenant packages', {
    appLocation,
    covenantConfig
  })
 
  // if there is a locked file already proceed no further. Error and exit
  const originalPackageJsonPath = `${appLocation}/package.json.interbit-hoist_backup`
  const isHoistAlreadyLocked = fs.existsSync(originalPackageJsonPath)
 
  if (isHoistAlreadyLocked) {
    log.error(
      'interbit-hoist: interbit-hoist.locked.package.json exists already.'
    )
    return
  }
 
  // make a locked original copy of the app's package dependencies (package-original.lock.json)
  const appPackageJsonPath = require.resolve(`${appLocation}/package.json`)
  fs.copyFileSync(appPackageJsonPath, originalPackageJsonPath)
 
  // Lift up all of the dependencies from covenant packages into the app dependencies
  // eslint-disable-next-line
  const appPackageJson = require(appPackageJsonPath)
  log.info('app found')
  const covenantPackageJsons = loadCovenantPackageJsons(covenantConfig)
  const hoistedDependencies = hoistAllCovenantPackages(
    appPackageJson,
    covenantPackageJsons
  )
 
  // Write the deps to package.json
  const hoistedPackageJson = {
    ...appPackageJson,
    dependencies: {
      ...hoistedDependencies.dependencies
    },
    devDependencies: {
      ...hoistedDependencies.devDependencies
    }
  }
  log.info('interbit-hoist: Writing new dependencies', hoistedPackageJson)
 
  writeJsonFile(appPackageJsonPath, hoistedPackageJson)
 
  // run npm i after all off the covenants have been hoisted
  const installDirectory = getArg(process.argv, '--install-dir') || appLocation
  await exec('npm install', { cwd: installDirectory })
 
  log.info('interbit-hoist: running npm i')
 
  // delete the tmp package.json and restore original
  fs.removeSync(appPackageJsonPath)
  fs.rename(originalPackageJsonPath, appPackageJsonPath)
 
  log.info('interbit-hoist: Restored original')
}
 
const loadCovenantPackageJsons = covenantConfig => {
  const covenantPackageJsons = []
 
  const covenantEntries = Object.entries(covenantConfig)
  covenantEntries.forEach(([name, config]) => {
    // eslint-disable-next-line
    const covenantPackageJson = require(`${config.location}/package.json`)
    log.info(`covenantPackageJson ${covenantPackageJson.name} found`)
    covenantPackageJsons.push(covenantPackageJson)
  })
 
  return covenantPackageJsons
}
 
const hoistAllCovenantPackages = (appPackageJson, covenantPackageJsons) => {
  let hoistedDependencies = { ...appPackageJson.dependencies }
  let hoistedDevDependencies = { ...appPackageJson.devDependencies }
 
  covenantPackageJsons.forEach(covenantPackageJson => {
    // eslint-disable-next-line
    hoistedDependencies = hoistDependencies(
      covenantPackageJson.name,
      hoistedDependencies,
      covenantPackageJson.dependencies
    )
    hoistedDevDependencies = hoistDependencies(
      covenantPackageJson.name,
      hoistedDevDependencies,
      covenantPackageJson.devDependencies
    )
  })
 
  return {
    dependencies: hoistedDependencies,
    devDependencies: hoistedDevDependencies
  }
}
 
const hoistDependencies = (covenant, appDependencies, covenantDependencies) => {
  if (!covenantDependencies) {
    return appDependencies
  }
 
  let hoisted = {
    ...appDependencies
  }
 
  // Check each covenant dependency
  Object.entries(covenantDependencies).forEach(([name, version]) => {
    // if it doesn't exist in the root app deps hoist it
    log.info(`Checking dependency... "${name}": "${version}" in ${covenant}`)
    const appDependency = appDependencies[name]
    if (typeof appDependency === 'undefined') {
      hoisted = {
        ...hoisted,
        [name]: version
      }
    } else Eif (appDependency !== version) {
      // If it does exist in the appDependencies but is a different version, give a warning
      log.warn(
        `HOIST: App version of "${name}": "${appDependency}" does not match version installed in covenant "${version}"`
      )
    }
  })
 
  return hoisted
}
 
module.exports = {
  hoistPackages,
  hoistAllCovenantPackages
}