All files / src/file updateIndexHtml.js

67.31% Statements 35/52
60% Branches 6/10
83.33% Functions 10/12
66.67% Lines 34/51
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 1052x 2x         2x   2x                   2x 3x 3x 3x 3x                   2x                               2x 4x 4x         4x 4x 4x     2x 4x 4x 16x   4x 8x 8x       2x 4x         4x 2x             2x 4x 4x         4x       2x 17x   2x          
const fs = require('fs-extra')
const cheerio = require('cheerio')
const {
  config: {
    selectors: { getApps }
  }
} = require('interbit-covenant-tools')
 
const log = require('../log')
 
/**
 * Updates the `index.html` files in the configured applications with their
 * configured peers and chain IDs so that browser nodes know how to connect
 * to the network.
 * @param {Object} params - The params object.
 * @param {Object} params.config - The interbit configuration specifying apps config.
 * @param {Object} params.chains - The chain alias to chain ID map to use.
 */
const updateIndexHtmls = ({ config, chains }) => {
  log.info({ config, chains })
  const apps = getApps(config)
  Eif (!apps) {
    return
  }
 
  const appsList = Object.entries(apps)
 
  appsList.forEach(([appName, appConfig]) => {
    updateIndexHtml({ appConfig, chains })
  })
}
 
const updateIndexHtml = ({ appConfig, chains }) => {
  log.info(appConfig)
  const indexHtmlFilepath = appConfig.indexLocation
 
  log.info('Updating index.html with chain data...', indexHtmlFilepath)
  const indexHtml = fs.readFileSync(indexHtmlFilepath).toString()
 
  const dom = cheerio.load(indexHtml)
  updateDom(dom, appConfig, chains)
 
  const updatedIndexHtml = `<!DOCTYPE html>\n${dom(':root').toString()}`
  fs.writeFileSync(indexHtmlFilepath, updatedIndexHtml)
 
  log.success('Finished updating index.html with chain IDs')
}
 
const updateDom = (dom, appConfig, chains) => {
  const interbitElement = dom('#interbit')
  Iif (!interbitElement.length) {
    log.error('ERR index.html must contain a <script> tag with [id="interbit"]')
    return
  }
 
  stripChainAttrs(interbitElement)
  insertChainsInDom(interbitElement, appConfig, chains)
  updateMetadata(interbitElement, appConfig)
}
 
const stripChainAttrs = interbitElement => {
  const interbitData = interbitElement.data()
  const chainIdDataAttrs = Object.keys(interbitData).filter(
    attr => attr.startsWith('chainId') || attr.startsWith('covenant')
  )
  chainIdDataAttrs.forEach(chainIdDataAttr => {
    const dataAttr = camelCaseToHyphenated(chainIdDataAttr)
    interbitElement.attr(`data-${dataAttr}`, null)
  })
}
 
const insertChainsInDom = (interbitElement, appConfig, chains) => {
  Iif (!chains) {
    log.error('No chains have been deployed to your node')
    return
  }
 
  appConfig.chains.forEach(chainAlias => {
    interbitElement.attr(
      `data-chain-id-${camelCaseToHyphenated(chainAlias)}`,
      chains[chainAlias]
    )
  })
}
 
const updateMetadata = (interbitElement, appConfig) => {
  const { peers } = appConfig
  Iif (!peers) {
    log.warn(
      'Interbit configuration file does not contain any peers for one of its apps'
    )
  } else {
    interbitElement.attr('data-peer-hints', peers.toString())
  }
}
 
const camelCaseToHyphenated = s =>
  s.replace(/\.?([A-Z]+)/g, (x, y) => `-${y.toLowerCase()}`).replace(/^_/, '')
 
module.exports = {
  updateIndexHtmls,
  updateDom,
  camelCaseToHyphenated
}