Last active
December 11, 2023 19:47
-
-
Save ethan605/4c657832d46d12408072fc2acdebf019 to your computer and use it in GitHub Desktop.
Boilerplate to quickly write a CLI tool with Node.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
/** | |
* A script to do something handy in an easy way | |
* | |
* For more info, run: | |
* $ <cli-name> --help | |
*/ | |
'use strict' | |
const fs = require('fs') | |
const COLORS = { | |
RESET: '\x1b[0m', | |
BRIGHT: '\x1b[1m', | |
DIM: '\x1b[2m', | |
UNDERSCORE: '\x1b[4m', | |
BLINK: '\x1b[5m', | |
REVERSE: '\x1b[7m', | |
HIDDEN: '\x1b[8m', | |
FG: { | |
BLACK: '\x1b[30m', | |
BLUE: '\x1b[34m', | |
CRIMSON: '\x1b[38m', | |
CYAN: '\x1b[36m', | |
GREEN: '\x1b[32m', | |
MAGENTA: '\x1b[35m', | |
RED: '\x1b[31m', | |
WHITE: '\x1b[37m', | |
YELLOW: '\x1b[33m', | |
}, | |
BG: { | |
BLACK: '\x1b[40m', | |
BLUE: '\x1b[44m', | |
CRIMSON: '\x1b[48m', | |
CYAN: '\x1b[46m', | |
GREEN: '\x1b[42m', | |
MAGENTA: '\x1b[45m', | |
RED: '\x1b[41m', | |
WHITE: '\x1b[47m', | |
YELLOW: '\x1b[43m', | |
}, | |
} | |
const COMMAND = '<cli-name>' | |
const VERSION = 'v1.0.0' | |
const PARSED_ARGS = {} | |
/* Helper functions */ | |
function buildColorMessage(message, ...colors) { | |
return [...colors, message, COLORS.RESET].join('') | |
} | |
function printError(message) { | |
console.error(buildColorMessage(`Error: ${message}`, COLORS.FG.RED)) | |
} | |
function verboseLogging(...args) { | |
if (!PARSED_ARGS.verbose) { | |
return | |
} | |
console.log(...args) | |
} | |
function printVersion() { | |
console.info(`<cli-name> ${VERSION} (c) 2020`) | |
process.exit(0) | |
} | |
function printHelp(errorMessage) { | |
if (errorMessage) { | |
printError(`${errorMessage}\n`) | |
} | |
console.info(`${COMMAND} - do something handy in an easy way | |
Usage: | |
${COMMAND} [options] [flags] | |
Examples: | |
${COMMAND} options... flags... | |
Available options: | |
-i, --in-file *required* Specify path to input file. | |
-o, --out-file Specify path to output JSON file. | |
If not specified, the result will be emitted to STDOUT. | |
Available flags: | |
-v, --verbose Verbose logging. | |
-V, --version Show the current version of the script. | |
-h, --help Show this message.`) | |
process.exit(errorMessage ? 1 : 0) | |
} | |
function parseOptionValue(name, trigger, params) { | |
const arg = params.shift() | |
if (!arg) { | |
printHelp(`Missing value for ${trigger} option`) | |
} | |
return { [name]: arg } | |
} | |
function validateOptions(parsedOptions) { | |
const { inFile } = parsedOptions | |
if (!inFile) { | |
printHelp('Missing --in-file|-i param') | |
} | |
if (!fs.existsSync(inFile)) { | |
printError('Input file not found') | |
process.exit(1) | |
} | |
// Other validations | |
} | |
function parseArgs() { | |
const params = process.argv.slice(2) | |
while (params.length) { | |
const args0 = params.shift() | |
switch (args0) { | |
case '--in-file': | |
case '-i': | |
Object.assign(PARSED_ARGS, parseOptionValue('inFile', args0, params)) | |
break | |
case '--out-file': | |
case '-o': | |
Object.assign(PARSED_ARGS, parseOptionValue('outFile', args0, params)) | |
break | |
case '--verbose': | |
case '-v': | |
Object.assign(PARSED_ARGS, { verbose: true }) | |
break | |
case '--version': | |
case '-V': | |
printVersion() | |
break | |
case '--help': | |
case '-h': | |
printHelp() | |
break | |
} | |
} | |
validateOptions(PARSED_ARGS) | |
} | |
/* Main functions */ | |
function main() { | |
parseArgs() | |
const { inFile, outFile } = PARSED_ARGS | |
const inputJson = JSON.parse(fs.readFileSync(inFile)) | |
const result = JSON.stringify(inputJson, null, 2) | |
verboseLogging('Reading data from', buildColorMessage(inFile, COLORS.FG.BLUE)) | |
if (!outFile) { | |
verboseLogging('\nProcessed data:') | |
console.info(result) | |
return | |
} | |
fs.writeFileSync(outFile, result) | |
console.info( | |
`Process written to ${buildColorMessage(outFile, COLORS.FG.GREEN)}` | |
) | |
} | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment