text: /**
  * @license Apache-2.0
  *
  * Copyright (c) 2018 The Stdlib Authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *    http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  
  'use strict';
  
  // MODULES //
  
  var parseArgs = require( 'minimist' );
  var notifier = require( 'update-notifier' ); // TODO: replace
  var objectKeys = require( '@stdlib/utils/keys' );
  var setReadOnly = require( '@stdlib/utils/define-nonenumerable-read-only-property' );
  var instanceOf = require( '@stdlib/assert/instance-of' );
  var copy = require( '@stdlib/utils/copy' );
  var isPlainObject = require( '@stdlib/assert/is-plain-object' );
  var stdout = require( '@stdlib/streams/node/stdout' );
  var stderr = require( '@stdlib/streams/node/stderr' );
  var ARGV = require( '@stdlib/process/argv' );
  var defaults = require( './defaults.json' );
  var validate = require( './validate.js' );
  var proc = require( './process.js' );
  var log = require( './console.js' );
  
  
  // MAIN //
  
  /**
  * Command-line interface constructor.
  *
  * @constructor
  * @param {Options} [options] - options
  * @param {Object} [options.pkg={}] - package meta information (package.json)
  * @param {string} [options.version] - command-line interface version
  * @param {string} [options.help=""] - help text
  * @param {(string|boolean)} [options.title=true] - process title or a boolean indicating whether to set the process title
  * @param {boolean} [options.updates=true] - boolean indicating whether to check if a command-line interface is an outdated version
  * @param {Array} [options.argv] - command-line arguments
  * @param {Options} [options.options={}] - command-line interface options
  * @throws {TypeError} must provide an object
  * @throws {TypeError} must provide valid options
  * @returns {CLI} command-line interface
  *
  * @example
  * var opts = {
  *     'pkg': require( './path/to/package.json' ),
  *     'help': 'Usage: beep [options] <boop>',
  *     'title': 'foo',
  *     'updates': true,
  *     'options': {
  *         'boolean': [
  *             'help',
  *             'version'
  *         ]
  *     }
  * };
  * var cli = new CLI( opts );
  * // returns <CLI>
  *
  * cli.exit();
  */
  function CLI( options ) {
  	var nopts;
  	var flags;
  	var keys;
  	var opts;
  	var self;
  	var argv;
  	var args;
  	var err;
  	if ( !instanceOf( this, CLI ) ) {
  		if ( arguments.length ) {
  			return new CLI( options );
  		}
  		return new CLI();
  	}
  	self = this;
  	opts = copy( defaults );
  	if ( arguments.length ) {
  		err = validate( opts, options );
  		if ( err ) {
  			throw err;
  		}
  	}
  	// Force the process to exit if an error is encountered when writing to `stdout` or `stderr`:
  	stdout.on( 'error', proc.exit );
  	stderr.on( 'error', proc.exit );
  
  	/**
  	* Returns parsed command-line arguments.
  	*
  	* @name args
  	* @memberof CLI#
  	* @type {Function}
  	* @returns {StringArray} parsed command-line arguments
  	*
  	* @example
  	* var cli = new CLI();
  	*
  	* var args = cli.args();
  	* // returns <Array>
  	*/
  	setReadOnly( this, 'args', getArgs );
  
  	/**
  	* Returns parsed command-line flags.
  	*
  	* @name flags
  	* @memberof CLI#
  	* @type {Function}
  	* @returns {Object} parsed command-line flags
  	*
  	* @example
  	* var cli = new CLI();
  	*
  	* var flags = cli.flags();
  	* // returns <Object>
  	*/
  	setReadOnly( this, 'flags', getFlags );
  
  	/**
  	* Prints usage information and exits the process.
  	*
  	* @name help
  	* @memberof CLI#
  	* @type {Function}
  	*
  	* @example
  	* var opts = {
  	*     'help': 'Usage: beep [options] <boop>'
  	* };
  	* var cli = new CLI( opts );
  	*
  	* cli.help();
  	* // => 'Usage: beep [options] <boop>'
  	*/
  	setReadOnly( this, 'help', help );
  
  	/**
  	* Prints the command-line interface version and exits the process.
  	*
  	* @name version
  	* @memberof CLI#
  	* @type {Function}
  	*
  	* @example
  	* var opts = {
  	*     'pkg': require( './path/to/package.json' )
  	* };
  	* var cli = new CLI( opts );
  	*
  	* cli.version();
  	* // => '#.#.#'
  	*/
  	setReadOnly( this, 'version', version );
  
  	// Check whether to set the process title...
  	if ( opts.title === true && opts.pkg ) {
  		if ( isPlainObject( opts.pkg.bin ) ) {
  			keys = objectKeys( opts.pkg.bin );
  
  			// Note: we don't have a way of knowing which command name in the `bin` hash was invoked; thus, we assume the first entry.
  			proc.title = keys[ 0 ];
  		} else if ( opts.pkg.name ) {
  			proc.title = opts.pkg.name;
  		}
  	} else if ( opts.title ) {
  		proc.title = opts.title;
  	}
  	// Check whether to notify the user of a new CLI version...
  	if ( opts.updates && opts.pkg && opts.pkg.name && opts.pkg.version ) {
  		nopts = {
  			'pkg': opts.pkg
  		};
  		notifier( nopts ).notify();
  	}
  	// Determine the command-line interface version...
  	if ( !opts.version && opts.pkg && opts.pkg.version ) {
  		opts.version = opts.pkg.version;
  	}
  	// Parse command-line arguments:
  	if ( opts.argv ) {
  		opts.argv = opts.argv.slice( 2 );
  	} else {
  		opts.argv = ARGV.slice( 2 );
  	}
  	argv = parseArgs( opts.argv, opts.options );
  
  	// Cache parsed arguments:
  	args = argv._;
  	delete argv._;
  	flags = argv;
  
  	// Determine whether to print help text...
  	if ( flags.help ) {
  		return this.help( 0 );
  	}
  	// Determine whether to print the version...
  	if ( flags.version ) {
  		return this.version();
  	}
  	return this;
  
  	/**
  	* Returns parsed command-line arguments.
  	*
  	* @private
  	* @returns {StringArray} parsed command-line arguments
  	*/
  	function getArgs() {
  		return args.slice();
  	}
  
  	/**
  	* Returns parsed command-line flags.
  	*
  	* @private
  	* @returns {Object} parsed command-line flags
  	*/
  	function getFlags() {
  		return copy( flags );
  	}
  
  	/**
  	* Prints usage information.
  	*
  	* ## Notes
  	*
  	* -   Upon printing usage information, the function forces the process to exit.
  	*
  	* @private
  	* @param {NonNegativeInteger} [code=0] - exit code
  	*/
  	function help( code ) {
  		log.error( opts.help );
  		self.exit( code || 0 );
  	}
  
  	/**
  	* Prints the command-line interface version.
  	*
  	* ## Notes
  	*
  	* -   Upon printing the version, the function forces the process to exit.
  	*
  	* @private
  	*/
  	function version() {
  		log.error( opts.version );
  		self.exit( 0 );
  	}
  }
  
  /**
  * Forces the command-line interface (and the process) to exit.
  *
  * @name exit
  * @memberof CLI.prototype
  * @type {Function}
  * @param {NonNegativeInteger} [code=0] - exit code
  */
  setReadOnly( CLI.prototype, 'exit', proc.exit );
  
  
  // EXPORTS //
  
  module.exports = CLI;
  