cmr1/node-cli

View on GitHub
docs/cli.js.html

Summary

Maintainability
Test Coverage
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>JSDoc: Source: cli.js</title>

    <script src="scripts/prettify/prettify.js"> </script>
    <script src="scripts/prettify/lang-css.js"> </script>
    <!--[if lt IE 9]>
      <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
    <![endif]-->
    <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
    <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>

<body>

<div id="main">

    <h1 class="page-title">Source: cli.js</h1>

    



    
    <section>
        <article>
            <pre class="prettyprint source linenums"><code>// Require extend for merging settings
const extend = require('extend')

// Require basic Logger class to extend from
const Logger = require('cmr1-logger')

// Require command-line-args to parse options from process.argv
const clArgs = require('command-line-args')

// Require command-line-usage to pair with clArgs to display usage info
const getUsage = require('command-line-usage')

// Require readline-sync for easy use of CLI input
const readLineSync = require('readline-sync')

/**
 * Cli Helper Class
 */
class Cli extends Logger {
  /**
   * Create a Cli object
   * @param {object} settings - The settings for this Cli object
   */
  constructor (settings = {}) {
    super()

    // Most things happen here, wrap it all up
    try {
      // Initialize options and settings
      this.options = {}
      this.settings = Object.assign({}, Cli.DEFAULT_SETTINGS) // Copys defaults settings into a NEW OBEJCT

      // Create Cli "alias" functions for reading input
      this.select = readLineSync.keyInSelect
      this.prompt = readLineSync.question
      this.confirm = readLineSync.keyInYN

      // Merge provided settings with defaults
      this.mergeSettings(settings)

      // Enable the logging based on settings
      this.enableLogging(this.settings.logging)

      // Parse and set options based on settings
      this.setOptions()

    // Catch an exception (Error)
    } catch (e) {
      // If we've already failed, force error output without throwing another Error
      this.options.force = true

      // Reference to logger function (
      // Verify function exists - thrown Error may have been from enableLogging() function
      const logger = (typeof this.error === 'function' ? this.error : console.error)

      // Print message using logger
      if (typeof e.message === 'string') {
        logger(e.message)

      // Print name using logger
      } else if (typeof e.name === 'string') {
        logger(e.name)

      // Print the entire Error using logger
      } else {
        logger(e)
      }

      // Output the entire error when verbose
      this.debug('Caught Error:', e)

      // Show the help menu &amp; exit the process
      this.showHelp()
    }

    // Show the help menu &amp; exit the process
    if (this.options.help) {
      this.showHelp()
    } else if (this.options.version) {
      this.showVersion()
    }
  }

  /**
   * Merge settings from constructor with defaults
   * @param {object} settings - The settings for this Cli object
   */
  mergeSettings (settings = {}) {
    // Only attempt to merge objects
    if (typeof settings === 'object') {
      // Loop through all keys in the provided settings object
      Object.keys(settings).forEach(key => {
        // Obtain the value from the current key
        const val = settings[key]

        // If the types of the values match, merge them
        if (typeof this.settings[key] === typeof val) {
          switch (typeof val) {
            // If the value is an object...
            case 'object':
              // If the both the default and the provided value are arrays, concat the two
              if (Array.isArray(this.settings[key]) &amp;&amp; Array.isArray(val)) {
                this.settings[key] = this.settings[key].concat(val)

              // If neither of the values are arrays, extend then (recursively)
              } else if (!Array.isArray(this.settings[key]) &amp;&amp; !Array.isArray(val)) {
                this.settings[key] = extend(true, this.settings[key], val)

              // Otherwise, we're attempting to merge incompatible settings!
              } else {
                throw new Error(`Cannot override setting: '${key}' ... Type did not match!`)
              }
              break

            // Otherwise, overwrite the value
            default:
              this.settings[key] = val
              break
          }

        // If there was no default, copy the new setting value!
        } else if (typeof this.settings[key] === 'undefined') {
          this.settings[key] = val
        }
      })
    } else {
      // Throw an Error if settings argument is not an object
      throw new Error('Invalid settings provided to merge function!')
    }
  }

  /**
   * Set the options from the process argument list (process.argv)
   */
  setOptions () {
    // Set options on this instance using clArgs (command-line-args)
    this.options = clArgs(this.settings.optionDefinitions)
  }

  /**
   * Get parsed CLI options
   */
  getOptions () {
    // Return the options object
    return this.options
  }

  /**
   * Return the JSON structure for the usage message
   */
  getHelpSections () {
    const sections = [
      {
        header: this.getVersionString(), // String - Main usage screen header
        content: this.settings.description // String - Main usage screen description
      }
    ]

    Object.keys(this.settings.helpSections).forEach(header => {
      let content = this.settings.helpSections[header]

      if (Array.isArray(content)) {
        content = content.join('\n')
      }

      sections.push({
        header: header.charAt(0).toUpperCase() + header.slice(1),
        content
      })
    })

    sections.push({
      header: this.settings.helpHeader, // String - Options header
      optionList: this.settings.optionDefinitions // Array - Option definitions
    })

    // Build simple config for command-line-usage module
    return sections
  }

  /**
   * Show the help menu &amp; exit
   */
  showHelp () {
    // Use console.log() for help (in case logging hasn't been enabled)
    console.log(getUsage(this.getHelpSections()))

    // Exit the process
    process.exit(0)
  }

  getVersionString () {
    return `${this.settings.name}  v${this.settings.version}`
  }

  /**
   * Show the name and current version
   */
  showVersion () {
    // Show name and version
    console.log(this.getVersionString())

    // Exit the process
    process.exit(0)
  }

  /**
   * Return the default settings from JSON file
   */
  static get DEFAULT_SETTINGS () {
    return require('../settings.json')
  }
}

// Export Cli class
module.exports = Cli
</code></pre>
        </article>
    </section>




</div>

<nav>
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Cli.html">Cli</a></li></ul>
</nav>

<br class="clear">

<footer>
    Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.2</a> on Wed Jul 24 2019 11:21:15 GMT-0600 (MDT)
</footer>

<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>