From 92ea84c5e93e8d432ab2d74da55c39ed92c46a9e Mon Sep 17 00:00:00 2001 From: stdlib-bot Date: Mon, 12 Jul 2021 20:57:10 +0000 Subject: [PATCH] Auto-generated commit --- bin/cli | 318 ++++++++++++----------------- {bin => docs}/usage.txt | 0 bin/opts.json => etc/cli_opts.json | 0 package.json | 7 +- test/test.cli.js | 142 +++++++++++++ 5 files changed, 282 insertions(+), 185 deletions(-) rename {bin => docs}/usage.txt (100%) rename bin/opts.json => etc/cli_opts.json (100%) create mode 100644 test/test.cli.js diff --git a/bin/cli b/bin/cli index 1786cde..27adbbe 100755 --- a/bin/cli +++ b/bin/cli @@ -22,211 +22,163 @@ // MODULES // -var fs = require( 'fs' ); -var path = require( 'path' ); -var parseArgs = require( 'minimist' ); +var resolve = require( 'path' ).resolve; +var readFileSync = require( '@stdlib/fs-read-file' ).sync; +var CLI = require( '@stdlib/cli-ctor' ); var ENV = require( '@stdlib/process-env' ); var cwd = require( '@stdlib/process-cwd' ); var stdin = require( '@stdlib/process-read-stdin' ); -var readFileSync = require( '@stdlib/fs-read-file' ).sync; -var pkg = require( './../package.json' ); -var opts = require( './opts.json' ); var httpServer = require( './../lib' ); -// FUNCTIONS // - -/** -* Performs initialization tasks. -* -* @private -* @example -* init(); -*/ -function init() { - // Set the process title to allow the process to be more easily identified: - process.title = pkg.name; - process.stdout.on( 'error', process.exit ); -} +// MAIN // /** -* Prints usage information. +* Main execution sequence. * * @private -* @example -* help(); -* // => '...' +* @returns {void} */ -function help() { - var fpath = path.join( __dirname, 'usage.txt' ); - fs.createReadStream( fpath ) - .pipe( process.stderr ) - .on( 'close', onClose ); - - function onClose() { - process.exit( 0 ); +function main() { + var fpath; + var flags; + var file; + var opts; + var cli; + var err; + var v; + + // Create a command-line interface: + cli = new CLI({ + 'pkg': require( './../package.json' ), + 'options': require( './../etc/cli_opts.json' ), + 'help': readFileSync( resolve( __dirname, '..', 'docs', 'usage.txt' ), { + 'encoding': 'utf8' + }) + }); + + // Get any provided command-line options: + flags = cli.flags(); + if ( flags.help || flags.version ) { + return; } -} - -/** -* Prints the package version. -* -* @private -* @example -* version(); -* // => '#.#.#' -*/ -function version() { - var msg = pkg.version.toString()+'\n'; - process.stdout.write( msg, 'utf8' ); - process.exit( 0 ); -} - -/** -* Writes an error message to `stderr` and then exits. -* -* @private -* @param {string} msg - error message -*/ -function exit( msg ) { - process.stderr.write( msg+'\n', 'utf8' ); - process.exit( 1 ); -} - - -// VARIABLES // - -var fpath; -var file; -var args; -var err; -var v; - - -// MAIN // - -init(); - -// Parse command-line arguments: -args = parseArgs( process.argv.slice( 2 ), opts ); - -if ( args.help ) { - return help(); -} -if ( args.version ) { - return version(); -} + opts = {}; -opts = {}; - -v = args.port || ENV.PORT; -if ( v ) { - opts.port = parseInt( v, 10 ); -} -v = args.maxport || ENV.MAXPORT; -if ( v ) { - opts.maxport = parseInt( v, 10 ); -} -v = args.hostname || ENV.HOSTNAME; -if ( v ) { - opts.hostname = v; -} -v = args.address || ENV.ADDRESS; -if ( v ) { - opts.address = v; -} -if ( args.open ) { - opts.open = true; -} - -// Load an HTML file... -if ( args.html ) { - fpath = path.resolve( cwd(), args.html ); - file = readFileSync( fpath ); - if ( file instanceof Error ) { - return exit( file.message ); + v = flags.port || ENV.PORT; + if ( v ) { + opts.port = parseInt( v, 10 ); } - opts.html = file; -} -// Load a JavaScript file... -if ( args.javascript ) { - fpath = path.resolve( cwd(), args.javascript ); - file = readFileSync( fpath ); - if ( file instanceof Error ) { - return exit( file.message ); + v = flags.maxport || ENV.MAXPORT; + if ( v ) { + opts.maxport = parseInt( v, 10 ); } - opts.javascript = file; -} -// Determine if we need to read data from `stdin`... -if ( args.stdin ) { - if ( args.stdin === 'html' ) { - return stdin( html ); - } else if ( - args.stdin === 'javascript' || - args.stdin === 'js' - ) { - return stdin( javascript ); + v = flags.hostname || ENV.HOSTNAME; + if ( v ) { + opts.hostname = v; } - err = new Error( 'invalid flag. Unrecognized/unsupported `stdin` type: '+args.stdin+'.' ); - return exit( err.message ); -} -// If the `stdin` flag has not been set and we're receiving data (i.e., not running in a terminal context), assume a content type based on either an `--html` or `--javascript` flag being set... -else if ( !process.stdin.isTTY ) { - if ( args.html ) { - return stdin( javascript ); - } else if ( args.javascript ) { - return stdin( html ); + v = flags.address || ENV.ADDRESS; + if ( v ) { + opts.address = v; + } + if ( flags.open ) { + opts.open = true; } - // Neither `--html` or `--javascript` was set... - err = new Error( 'invalid invocation. Must specify a `stdin` content type.' ); - return exit( err.message ); -} - -return process.nextTick( next ); -/** -* Callback invoked after attempting to read HTML from `stdin`. -* -* @private -* @param {(Error|null)} error - error object -* @param {Buffer} data - `stdin` data -*/ -function html( error, data ) { - if ( error ) { - return exit( error.message ); + // Load an HTML file... + if ( flags.html ) { + fpath = resolve( cwd(), flags.html ); + file = readFileSync( fpath ); + if ( file instanceof Error ) { + return cli.error( file ); + } + opts.html = file; } - if ( data.toString() === '' ) { - error = new Error( 'no input data. Provide either a path to an HTML file or provide HTML via `stdin`.' ); - return exit( error.message ); + // Load a JavaScript file... + if ( flags.javascript ) { + fpath = resolve( cwd(), flags.javascript ); + file = readFileSync( fpath ); + if ( file instanceof Error ) { + return cli.error( file ); + } + opts.javascript = file; + } + // Determine if we need to read data from `stdin`... + if ( flags.stdin ) { + if ( flags.stdin === 'html' ) { + return stdin( html ); + } + if ( + flags.stdin === 'javascript' || + flags.stdin === 'js' + ) { + return stdin( javascript ); + } + err = new Error( 'invalid flag. Unrecognized/unsupported `stdin` type: '+flags.stdin+'.' ); + return cli.error( err ); + } + // If the `stdin` flag has not been set and we're receiving data (i.e., not running in a terminal context), assume a content type based on either an `--html` or `--javascript` flag being set... + if ( !process.stdin.isTTY ) { + if ( flags.html ) { + return stdin( javascript ); + } + if ( flags.javascript ) { + return stdin( html ); + } + // Neither `--html` or `--javascript` was set... + err = new Error( 'invalid invocation. Must specify a `stdin` content type.' ); + return cli.error( err ); } - opts.html = data; - next(); -} -/** -* Callback invoked after attempting to read JavaScript from `stdin`. -* -* @private -* @param {(Error|null)} error - error object -* @param {Buffer} data - `stdin` data -*/ -function javascript( error, data ) { - if ( error ) { - return exit( error.message ); + return process.nextTick( next ); + + /** + * Callback invoked after attempting to read HTML from `stdin`. + * + * @private + * @param {(Error|null)} error - error object + * @param {Buffer} data - `stdin` data + * @returns {void} + */ + function html( error, data ) { + if ( error ) { + return cli.error( error ); + } + if ( data.toString() === '' ) { + error = new Error( 'no input data. Provide either a path to an HTML file or provide HTML via `stdin`.' ); + return cli.error( error ); + } + opts.html = data; + next(); } - if ( data.toString() === '' ) { - error = new Error( 'no input data. Provide either a path to a JavaScript file or provide JavaScript via `stdin`.' ); - return exit( error.message ); + + /** + * Callback invoked after attempting to read JavaScript from `stdin`. + * + * @private + * @param {(Error|null)} error - error object + * @param {Buffer} data - `stdin` data + * @returns {void} + */ + function javascript( error, data ) { + if ( error ) { + return cli.error( error ); + } + if ( data.toString() === '' ) { + error = new Error( 'no input data. Provide either a path to a JavaScript file or provide JavaScript via `stdin`.' ); + return cli.error( error ); + } + opts.javascript = data; + next(); } - opts.javascript = data; - next(); -} -/** -* Callback invoked once ready to run an HTTP server. -* -* @private -*/ -function next() { - httpServer( opts ); + /** + * Callback invoked once ready to run an HTTP server. + * + * @private + */ + function next() { + httpServer( opts ); + } } + +main(); diff --git a/bin/usage.txt b/docs/usage.txt similarity index 100% rename from bin/usage.txt rename to docs/usage.txt diff --git a/bin/opts.json b/etc/cli_opts.json similarity index 100% rename from bin/opts.json rename to etc/cli_opts.json diff --git a/package.json b/package.json index cbe2629..79ecdb3 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "@stdlib/assert-is-string": "^0.0.x", "@stdlib/buffer-ctor": "^0.0.x", "@stdlib/buffer-from-string": "^0.0.x", + "@stdlib/cli-ctor": "^0.0.x", "@stdlib/fs-read-file": "^0.0.x", "@stdlib/net-http-server": "^0.0.x", "@stdlib/process-cwd": "^0.0.x", @@ -55,10 +56,12 @@ "@stdlib/utils-next-tick": "^0.0.x", "@stdlib/utils-noop": "^0.0.x", "@stdlib/utils-open-url": "^0.0.x", - "debug": "^2.6.9", - "minimist": "^1.2.0" + "debug": "^2.6.9" }, "devDependencies": { + "@stdlib/assert-is-browser": "^0.0.x", + "@stdlib/assert-is-windows": "^0.0.x", + "@stdlib/process-exec-path": "^0.0.x", "proxyquire": "^2.0.0", "tape": "git+https://github.com/kgryte/tape.git#fix/globby", "istanbul": "^0.4.1", diff --git a/test/test.cli.js b/test/test.cli.js new file mode 100644 index 0000000..9e4cbb1 --- /dev/null +++ b/test/test.cli.js @@ -0,0 +1,142 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2021 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 resolve = require( 'path' ).resolve; +var exec = require( 'child_process' ).exec; +var tape = require( 'tape' ); +var IS_BROWSER = require( '@stdlib/assert-is-browser' ); +var IS_WINDOWS = require( '@stdlib/assert-is-windows' ); +var EXEC_PATH = require( '@stdlib/process-exec-path' ); +var readFileSync = require( '@stdlib/fs-read-file' ).sync; + + +// VARIABLES // + +var fpath = resolve( __dirname, '..', 'bin', 'cli' ); +var opts = { + 'skip': IS_BROWSER || IS_WINDOWS +}; + + +// FIXTURES // + +var PKG_VERSION = require( './../package.json' ).version; + + +// TESTS // + +tape( 'command-line interface', function test( t ) { + t.ok( true, __filename ); + t.end(); +}); + +tape( 'when invoked with a `--help` flag, the command-line interface prints the help text to `stderr`', opts, function test( t ) { + var expected; + var cmd; + + expected = readFileSync( resolve( __dirname, '..', 'docs', 'usage.txt' ), { + 'encoding': 'utf8' + }); + cmd = [ + EXEC_PATH, + fpath, + '--help' + ]; + + exec( cmd.join( ' ' ), done ); + + function done( error, stdout, stderr ) { + if ( error ) { + t.fail( error.message ); + } else { + t.strictEqual( stdout.toString(), '', 'does not print to `stdout`' ); + t.strictEqual( stderr.toString(), expected+'\n', 'expected value' ); + } + t.end(); + } +}); + +tape( 'when invoked with a `-h` flag, the command-line interface prints the help text to `stderr`', opts, function test( t ) { + var expected; + var cmd; + + expected = readFileSync( resolve( __dirname, '..', 'docs', 'usage.txt' ), { + 'encoding': 'utf8' + }); + cmd = [ + EXEC_PATH, + fpath, + '-h' + ]; + + exec( cmd.join( ' ' ), done ); + + function done( error, stdout, stderr ) { + if ( error ) { + t.fail( error.message ); + } else { + t.strictEqual( stdout.toString(), '', 'does not print to `stdout`' ); + t.strictEqual( stderr.toString(), expected+'\n', 'expected value' ); + } + t.end(); + } +}); + +tape( 'when invoked with a `--version` flag, the command-line interface prints the version to `stderr`', opts, function test( t ) { + var cmd = [ + EXEC_PATH, + fpath, + '--version' + ]; + + exec( cmd.join( ' ' ), done ); + + function done( error, stdout, stderr ) { + if ( error ) { + t.fail( error.message ); + } else { + t.strictEqual( stdout.toString(), '', 'does not print to `stdout`' ); + t.strictEqual( stderr.toString(), PKG_VERSION+'\n', 'expected value' ); + } + t.end(); + } +}); + +tape( 'when invoked with a `-V` flag, the command-line interface prints the version to `stderr`', opts, function test( t ) { + var cmd = [ + EXEC_PATH, + fpath, + '-V' + ]; + + exec( cmd.join( ' ' ), done ); + + function done( error, stdout, stderr ) { + if ( error ) { + t.fail( error.message ); + } else { + t.strictEqual( stdout.toString(), '', 'does not print to `stdout`' ); + t.strictEqual( stderr.toString(), PKG_VERSION+'\n', 'expected value' ); + } + t.end(); + } +});