diff --git a/package-lock.json b/package-lock.json index 0c02f6c..34ed1a4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -529,13 +529,25 @@ "integrity": "sha512-Ups2dShK52xXa8w6iBWLgcjPJWjais6KPJQq3gQ/88AY6BXoTX+MIGFPrWQO1KLMiQfoTpcLnUwloN4brrVUHw==" }, "@oclif/parser": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/@oclif/parser/-/parser-3.7.2.tgz", - "integrity": "sha512-ssYXztaf9TuOGCJQOYMg62L1Q4y2lB4wZORWng+Iy0ckP2A6IUnQy97V8YjAJkkohYZOu3Mga8LGfQcf+xdIIw==", + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/@oclif/parser/-/parser-3.8.3.tgz", + "integrity": "sha512-zN+3oGuv9Lg8NjFvxZTDKFEmhAMfAvd/JWeQp3Ri8pDezoyJQi4OSHHLM8sdHjBh8sePewfWI7+fDUXdrVbrqg==", "requires": { "@oclif/linewrap": "^1.0.0", - "chalk": "^2.4.1", + "chalk": "^2.4.2", "tslib": "^1.9.3" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } } }, "@oclif/plugin-help": { diff --git a/package.json b/package.json index 2b6ee8d..89d3c69 100644 --- a/package.json +++ b/package.json @@ -72,6 +72,7 @@ "dependencies": { "@iarna/toml": "^2.2.1", "@oclif/command": "^1.5.8", + "@oclif/parser": "^3.8.3", "chalk": "^2.4.1", "ci-info": "^2.0.0", "cli-ux": "^5.0.0", diff --git a/src/index.js b/src/index.js index f06c5a0..3916399 100644 --- a/src/index.js +++ b/src/index.js @@ -1,14 +1,16 @@ const { Command } = require('@oclif/command') -const chalk = require('chalk') const API = require('netlify') +const merge = require('lodash.merge') +const { format, inspect } = require('util') const getConfigPath = require('./utils/get-config-path') const readConfig = require('./utils/read-config') const globalConfig = require('./global-config') const StateConfig = require('./state') +const chalkInstance = require('./utils/chalk') const openBrowser = require('./utils/open-browser') const findRoot = require('./utils/find-root') const { track, identify } = require('./utils/telemetry') -const merge = require('lodash.merge') + const argv = require('minimist')(process.argv.slice(2)) const { NETLIFY_AUTH_TOKEN } = process.env @@ -24,7 +26,9 @@ class BaseCommand extends Command { async init(err) { const projectRoot = findRoot(process.cwd()) // Grab netlify API token - const [ token ] = this.getConfigToken(argv.auth) + const authViaFlag = getAuthArg(argv) + + const [ token ] = this.getConfigToken(authViaFlag) // Get site config from netlify.toml const configPath = getConfigPath(projectRoot) // TODO: https://github.com/request/caseless to handle key casing issues @@ -65,6 +69,69 @@ class BaseCommand extends Command { } } + logJson(message = '', ...args) { + /* Only run json logger when --json flag present */ + if (!argv.json) { + return + } + process.stdout.write(JSON.stringify(message, null, 2)) + } + + log(message = '', ...args) { + /* If --silent or --json flag passed disable logger */ + if (argv.silent || argv.json) { + return + } + message = typeof message === 'string' ? message : inspect(message) + process.stdout.write(format(message, ...args) + '\n') + } + + /* Modified flag parser to support global --auth, --json, & --silent flags */ + parse(opts, argv = this.argv) { + /* Set flags object for commands without flags */ + if (!opts.flags) { + opts.flags = {} + } + /* enrich parse with global flags */ + const globalFlags = {} + if (!opts.flags.silent) { + globalFlags['silent'] = { + parse: (b, _) => b, + description: 'Silence CLI output', + allowNo: false, + type: 'boolean' + } + } + if (!opts.flags.json) { + globalFlags['json'] = { + parse: (b, _) => b, + description: 'Output return values as JSON', + allowNo: false, + type: 'boolean' + } + } + if (!opts.flags.auth) { + globalFlags['auth'] = { + parse: (b, _) => b, + description: 'Netlify auth token', + input: [], + multiple: false, + type: 'option' + } + } + + // enrich with flags here + opts.flags = Object.assign({}, opts.flags, globalFlags) + + return require('@oclif/parser').parse(argv, Object.assign({}, { + context: this, + }, opts)) + } + + get chalk() { + // If --json flag disable chalk colors + return chalkInstance(argv.json) + } /** * Get user netlify API token * @param {string} - [tokenFromFlag] - value passed in by CLI flag @@ -150,14 +217,22 @@ class BaseCommand extends Command { // Log success this.log() - this.log(`${chalk.greenBright('You are now logged into your Netlify account!')}`) + this.log(`${this.chalk.greenBright('You are now logged into your Netlify account!')}`) this.log() - this.log(`Run ${chalk.cyanBright('netlify status')} for account details`) + this.log(`Run ${this.chalk.cyanBright('netlify status')} for account details`) this.log() - this.log(`To see all available commands run: ${chalk.cyanBright('netlify help')}`) + this.log(`To see all available commands run: ${this.chalk.cyanBright('netlify help')}`) this.log() return accessToken } } -module.exports = BaseCommand \ No newline at end of file +function getAuthArg(cliArgs) { + // If deploy command. Support shorthand 'a' flag + if (cliArgs && cliArgs._ && cliArgs._[0] === 'deploy') { + return cliArgs.auth || cliArgs.a + } + return cliArgs.auth +} + +module.exports = BaseCommand diff --git a/src/utils/chalk.js b/src/utils/chalk.js new file mode 100644 index 0000000..358ef3b --- /dev/null +++ b/src/utils/chalk.js @@ -0,0 +1,48 @@ +const chalk = require('chalk') + +/** + * Chalk instance for CLI + * @param {boolean} noColors - disable chalk colors + * @return {object} - chalk instance or proxy noOp + */ +function safeChalk(noColors) { + /* if no colors return proxy to chalk API */ + if (noColors) { + return neverNull(chalk) + } + return chalk +} + +function noop() {} + +function neverNull(obj) { + function match(some, none = noop) { + return obj != null ? some(obj) : none() + } + return new Proxy((some, none) => { + if (some) { + // has value return it with no chalk wrapper + return some + } + if (!some && !none) return obj + return match(some, none) + }, { + get: (target, key) => { + const obj = target() + if (obj !== null && typeof obj === 'object') { + return neverNull(obj[key]) + } else { + return neverNull() + } + }, + set: (target, key, val) => { + const obj = target() + if (obj !== null && typeof obj === 'object') { + obj[key] = val + } + return true + } + }) +} + +module.exports = safeChalk \ No newline at end of file