nielse63/launch-checklist

View on GitHub
lib/utils.js

Summary

Maintainability
B
4 hrs
Test Coverage

import url from 'url'
import validator from 'validator'
import clc from 'cli-color'
import _ from 'lodash'

export const hasKey = function (object, key) {
  return _.has(object, key)
}

export const isLocalhost = function (string) {
  return validator.matches(String(string), /localhost|127\.0\.0\.1/i)
}

export const addProtocol = function (str) {
  let string = validator.ltrim(str, '/')
  if (!validator.matches(string, /^http/)) {
    string = `http://${string}`
  }
  const parsedUrl = url.parse(string)
  return validator.rtrim(url.format(parsedUrl), '/')
}

export const cleanURL = function (str) {
  if (!str) {
    throw new Error('No URL provided. Exiting')
  }

  const string = validator.trim(str.toString(), '/')
  const withProtocol = addProtocol(string)

  const options = {
    protocols: ['http', 'https'],
    require_protocol: true, // eslint-disable-line camelcase
  }
  if (!validator.isURL(withProtocol, options)) {
    throw new Error(`Invalid URL (${str}) provided. Exiting`)
  }

  return withProtocol
}

/* eslint-disable max-statements */
export const wordWrap = function (string, max = 80) {
  function getWords(str) {
    return str
      .toString()
      .split(/(\S+\s+)/)
      .reduce((acc, x) => {
        acc.push(x)
        return acc
      }, [])
  }

  function getLines(words) {
    return words.reduce((lines, word) => {
      if (word === '') {
        return lines
      }
      const chunk = word.replace(/\t/g, '    ')
      const i = lines.length - 1
      if (lines[i].length + chunk.length > max) {
        lines[i] = lines[i].replace(/\s+$/, '')
        chunk.split(/\n/).forEach(c => {
          lines.push(
            new Array(1).join(' ') + c.replace(/^\s+/, ''),
          )
        })
      } else if (chunk.match(/\n/)) {
        const xs = chunk.split(/\n/)
        lines[i] += xs.shift()
        xs.forEach(c => {
          lines.push(
            new Array(1).join(' ') + c.replace(/^\s+/, ''),
          )
        })
      } else {
        lines[i] += chunk
      }
      return lines
    }, [new Array(1).join(' ')])
  }

  const words = getWords(string)
  let output = getLines(words)

  // line up to first indent
  const idx = output[0].search(/\w/)
  if (idx) {
    output = output.map((line, i) => {
      if (!i) {
        return line
      }
      return ' '.repeat(idx) + line
    })
  }

  // prevent widows
  const lastLine = output[output.length - 1].trim()
  if (lastLine.split(/(\S+\s+)/).length === 1) {
    output[output.length - 2] += ` ${lastLine}`
    output.pop()
  }

  return output.join('\n')
}
/* eslint-enable max-statements */

export const getDetails = function (test) {
  if (test.passed && hasKey(test, 'success')) {
    test.reason = test.success
  }

  const output = [test.reason]
  if (!hasKey(test, 'info')) {
    return output[0]
  }

  output[0] += ':'
  const width = clc.windowSize.width / 2
  const values = test.info.map(object => {
    const title = typeof object === 'string' ? object : object.title
    return wordWrap(` - ${title}`, width)
  })
  const array = [...new Set(values)]
  return output.concat(array).join('\n')
}

export const getInsightsURL = function (req, strategy = 'desktop') {
  const ping = encodeURIComponent(req)
  return `https://www.googleapis.com/pagespeedonline/v2/runPagespeed?url=${ping}&screenshot=false&strategy=${strategy}`
}

export const getElement = function ($element, key) {
  return {
    passed: !!$element.length,
    reason: `Missing ${key}`,
  }
}

export const getTestResults = function (info, msg) {
  return {
    passed: !info.length,
    reason: `${info.length} ${msg} found`,
    info,
  }
}

export const printTableHeader = function (title) {
  if (!title) {
    return ''
  }

  return [
    '',
    `Results - ${title}`,
    '='.repeat(30),
  ]
}

export const IN_DEBUG = hasKey(process.env, 'NODE_ENV') && process.env.NODE_ENV.toLowerCase() === 'debug'

export const killReport = function (data) {
  /* eslint complexity: ["error", 5] */
  if (!_.isPlainObject(data)) {
    throw new Error('Supplied data is not a JavaScript object')
  }

  if (!_.has(data, 'output')) {
    throw new Error('Object does not have key `output`')
  }

  if (!_.isPlainObject(data.output)) {
    throw new Error('Output value is not a JavaScript object')
  }

  if (!_.isPlainObject(data.settings)) {
    throw new Error('Settings value is not a JavaScript object')
  }
}