@oclif/core
Advanced tools
Comparing version 0.2.0 to 0.3.0
@@ -0,1 +1,21 @@ | ||
# [0.3.0](https://github.com/oclif/core/compare/v0.2.0...v0.3.0) (2021-02-01) | ||
### Bug Fixes | ||
* default ExitError to exit error code 1 ([#95](https://github.com/oclif/core/issues/95)) ([2005c5f](https://github.com/oclif/core/commit/2005c5f092dc60c0cfafcb1d5c90fd62c2048dca)) | ||
* filter help argvs before invoking ([#103](https://github.com/oclif/core/issues/103)) ([698125d](https://github.com/oclif/core/commit/698125d602de9bc085b4080768a564a7b01fe27d)) | ||
* only --version & --help are special global flags ([#96](https://github.com/oclif/core/issues/96)) ([364d6dd](https://github.com/oclif/core/commit/364d6dd8fd5a54334a6e77255cd6b3a5e7321632)) | ||
### Features | ||
* add default command (rm root cmd) ([#97](https://github.com/oclif/core/issues/97)) ([fbf1a0f](https://github.com/oclif/core/commit/fbf1a0f827208da75c77009fedd48b8886a00520)) | ||
* args read stdin ([#100](https://github.com/oclif/core/issues/100)) ([caea554](https://github.com/oclif/core/commit/caea55484c0cdf6803b9fa472f9fa8a622f57a80)) | ||
* parse async ([#99](https://github.com/oclif/core/issues/99)) ([57924df](https://github.com/oclif/core/commit/57924df5c168b677df9d1d1f43155a89e9cb2c98)) | ||
* rm duplicate ts-node registering ([#102](https://github.com/oclif/core/issues/102)) ([b8b5333](https://github.com/oclif/core/commit/b8b5333047eb939e79c8cadf460e3c76ff751460)) | ||
* run single & multi cmd clis with same invoking/runner ([#98](https://github.com/oclif/core/issues/98)) ([8828ca9](https://github.com/oclif/core/commit/8828ca9d05f87bc321bbd2394191b194764bba7a)) | ||
# [0.2.0](https://github.com/oclif/core/compare/v0.1.2...v0.2.0) (2020-09-18) | ||
@@ -2,0 +22,0 @@ |
@@ -67,8 +67,5 @@ import * as Interfaces from './interfaces'; | ||
[name: string]: any; | ||
}>(options?: Interfaces.Input<F>, argv?: string[]): Interfaces.ParserOutput<F, A>; | ||
}>(options?: Interfaces.Input<F>, argv?: string[]): Promise<Interfaces.ParserOutput<F, A>>; | ||
protected catch(err: any): Promise<any>; | ||
protected finally(_: Error | undefined): Promise<any>; | ||
protected _help(): never; | ||
protected _helpOverride(): boolean; | ||
protected _version(): never; | ||
} |
@@ -7,4 +7,2 @@ "use strict"; | ||
const Parser = require("./parser"); | ||
const help_1 = require("./help"); | ||
const util_2 = require("./util"); | ||
const pjson = require('../package.json'); | ||
@@ -82,6 +80,4 @@ /** | ||
g['http-call'].userAgent = this.config.userAgent; | ||
if (this._helpOverride()) | ||
return this._help(); | ||
} | ||
parse(options, argv = this.argv) { | ||
async parse(options, argv = this.argv) { | ||
if (!options) | ||
@@ -94,8 +90,2 @@ options = this.constructor; | ||
throw err; | ||
if (err.message.match(/Unexpected arguments?: (-h|--help|help)(,|\n)/)) { | ||
return this._help(); | ||
} | ||
if (err.message.match(/Unexpected arguments?: (-v|--version|version)(,|\n)/)) { | ||
return this._version(); | ||
} | ||
try { | ||
@@ -120,28 +110,2 @@ const { cli } = require('cli-ux'); | ||
} | ||
_help() { | ||
const HelpClass = help_1.getHelpClass(this.config); | ||
const help = new HelpClass(this.config); | ||
const cmd = config_1.toCached(this.ctor); | ||
if (!cmd.id) | ||
cmd.id = ''; | ||
let topics = this.config.topics; | ||
topics = topics.filter((t) => !t.hidden); | ||
topics = util_2.sortBy(topics, (t) => t.name); | ||
topics = util_2.uniqBy(topics, (t) => t.name); | ||
help.showCommandHelp(cmd, topics); | ||
return this.exit(0); | ||
} | ||
_helpOverride() { | ||
for (const arg of this.argv) { | ||
if (arg === '--help') | ||
return true; | ||
if (arg === '--') | ||
return false; | ||
} | ||
return false; | ||
} | ||
_version() { | ||
this.log(this.config.userAgent); | ||
return this.exit(0); | ||
} | ||
} | ||
@@ -148,0 +112,0 @@ exports.default = Command; |
@@ -10,3 +10,2 @@ "use strict"; | ||
const util_3 = require("./util"); | ||
const ROOT_INDEX_CMD_ID = ''; | ||
const _pjson = require('../../package.json'); | ||
@@ -152,5 +151,2 @@ const hasManifest = function (p) { | ||
const command = p.name !== 'index' && p.name; | ||
// support src/commands/index as a "root" command | ||
if (!command && this.type === 'core' && p.dir.length === 0 && p.name === 'index') | ||
return ROOT_INDEX_CMD_ID; | ||
return [...topics, command].filter(f => f).join(':'); | ||
@@ -157,0 +153,0 @@ }); |
@@ -8,5 +8,2 @@ "use strict"; | ||
const debug = util_1.Debug(); | ||
const tsconfigs = {}; | ||
const rootDirs = []; | ||
const typeRoots = [`${__dirname}/../node_modules/@types`]; | ||
function loadTSConfig(root) { | ||
@@ -33,46 +30,2 @@ const tsconfigPath = path.join(root, 'tsconfig.json'); | ||
} | ||
function registerTSNode(root) { | ||
if (process.env.OCLIF_TS_NODE === '0') | ||
return; | ||
if (tsconfigs[root]) | ||
return; | ||
const tsconfig = loadTSConfig(root); | ||
if (!tsconfig) | ||
return; | ||
debug('registering ts-node at', root); | ||
const tsNodePath = require.resolve('ts-node', { paths: [root, __dirname] }); | ||
const tsNode = require(tsNodePath); | ||
tsconfigs[root] = tsconfig; | ||
typeRoots.push(`${root}/node_modules/@types`); | ||
if (tsconfig.compilerOptions.rootDirs) { | ||
rootDirs.push(...tsconfig.compilerOptions.rootDirs.map(r => path.join(root, r))); | ||
} | ||
else { | ||
rootDirs.push(`${root}/src`); | ||
} | ||
const cwd = process.cwd(); | ||
try { | ||
process.chdir(root); | ||
tsNode.register({ | ||
skipProject: true, | ||
transpileOnly: true, | ||
// cache: false, | ||
// typeCheck: true, | ||
compilerOptions: { | ||
esModuleInterop: tsconfig.compilerOptions.esModuleInterop, | ||
target: tsconfig.compilerOptions.target || 'es2017', | ||
experimentalDecorators: tsconfig.compilerOptions.experimentalDecorators || false, | ||
emitDecoratorMetadata: tsconfig.compilerOptions.emitDecoratorMetadata || false, | ||
module: 'commonjs', | ||
sourceMap: true, | ||
rootDirs, | ||
typeRoots, | ||
jsx: 'react', | ||
}, | ||
}); | ||
} | ||
finally { | ||
process.chdir(cwd); | ||
} | ||
} | ||
function tsPath(root, orig) { | ||
@@ -83,4 +36,3 @@ if (!orig) | ||
try { | ||
registerTSNode(root); | ||
const tsconfig = tsconfigs[root]; | ||
const tsconfig = loadTSConfig(root); | ||
if (!tsconfig) | ||
@@ -87,0 +39,0 @@ return orig; |
@@ -5,3 +5,3 @@ "use strict"; | ||
class ExitError extends cli_1.CLIError { | ||
constructor(exitCode = 0) { | ||
constructor(exitCode = 1) { | ||
super(`EEXIT: ${exitCode}`, { exit: exitCode }); | ||
@@ -8,0 +8,0 @@ this.code = 'EEXIT'; |
@@ -13,3 +13,3 @@ "use strict"; | ||
const _enum = (opts) => { | ||
return build(Object.assign({ parse(input) { | ||
return build(Object.assign({ async parse(input) { | ||
if (!opts.options.includes(input)) | ||
@@ -29,3 +29,3 @@ throw new Error(`Expected --${this.name}=${input} to be one of: ${opts.options.join(', ')}`); | ||
// char: 'v', | ||
description: 'show CLI version' }, opts), { parse: (_, cmd) => { | ||
description: 'show CLI version' }, opts), { parse: async (_, cmd) => { | ||
cmd.log(cmd.config.userAgent); | ||
@@ -38,5 +38,5 @@ cmd.exit(0); | ||
// char: 'h', | ||
description: 'show CLI help' }, opts), { parse: (_, cmd) => { | ||
description: 'show CLI help' }, opts), { parse: async (_, cmd) => { | ||
cmd._help(); | ||
} })); | ||
}; |
@@ -17,3 +17,2 @@ "use strict"; | ||
const { bold, } = Chalk; | ||
const ROOT_INDEX_CMD_ID = ''; | ||
function getHelpSubject(args) { | ||
@@ -23,3 +22,3 @@ for (const arg of args) { | ||
return; | ||
if (arg === 'help' || arg === '--help' || arg === '-h') | ||
if (arg === 'help' || arg === '--help') | ||
continue; | ||
@@ -73,5 +72,7 @@ if (arg.startsWith('-')) | ||
if (!subject) { | ||
const rootCmd = this.config.findCommand(ROOT_INDEX_CMD_ID); | ||
if (rootCmd) | ||
this.showCommandHelp(rootCmd); | ||
if (this.config.pjson.oclif.default) { | ||
const rootCmd = this.config.findCommand(this.config.pjson.oclif.default); | ||
if (rootCmd) | ||
this.showCommandHelp(rootCmd); | ||
} | ||
this.showRootHelp(); | ||
@@ -78,0 +79,0 @@ return; |
import { AlphabetLowercase, AlphabetUppercase } from './alphabet'; | ||
import { Config } from './config'; | ||
export declare type ParseFn<T> = (input: string) => T; | ||
export declare type ParseFn<T> = (input: string) => Promise<T>; | ||
export interface Arg<T = string> { | ||
@@ -12,2 +12,3 @@ name: string; | ||
options?: string[]; | ||
ignoreStdin?: boolean; | ||
} | ||
@@ -19,5 +20,6 @@ export interface ArgBase<T> { | ||
parse: ParseFn<T>; | ||
default?: T | (() => T); | ||
default?: T | (() => Promise<T>); | ||
input?: string; | ||
options?: string[]; | ||
ignoreStdin?: boolean; | ||
} | ||
@@ -85,3 +87,3 @@ export declare type RequiredArg<T> = ArgBase<T> & { | ||
}; | ||
export declare type Default<T> = T | ((context: DefaultContext<T>) => T); | ||
export declare type Default<T> = T | ((context: DefaultContext<T>) => Promise<T>); | ||
export declare type FlagBase<T, I> = { | ||
@@ -101,3 +103,3 @@ name: string; | ||
env?: string; | ||
parse(input: I, context: any): T; | ||
parse(input: I, context: any): Promise<T>; | ||
}; | ||
@@ -104,0 +106,0 @@ export declare type BooleanFlag<T> = FlagBase<T, boolean> & { |
@@ -22,2 +22,3 @@ export interface PJSON { | ||
commands?: string; | ||
default?: string; | ||
plugins?: string[]; | ||
@@ -24,0 +25,0 @@ devPlugins?: string[]; |
import * as Interfaces from './interfaces'; | ||
import Command from './command'; | ||
export declare class Main extends Command { | ||
static run(argv?: string[], options?: Interfaces.LoadOptions): PromiseLike<any>; | ||
init(): Promise<any>; | ||
run(): Promise<undefined>; | ||
protected _helpOverride(): boolean; | ||
protected _help(): never; | ||
} | ||
export declare function run(argv?: string[], options?: Interfaces.LoadOptions): PromiseLike<any>; | ||
export declare function run(argv?: string[], options?: Interfaces.LoadOptions): Promise<void>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const util_1 = require("util"); | ||
const config_1 = require("./config"); | ||
const help_1 = require("./help"); | ||
const command_1 = require("./command"); | ||
const ROOT_INDEX_CMD_ID = ''; | ||
class Main extends command_1.default { | ||
static run(argv = process.argv.slice(2), options) { | ||
return super.run(argv, options || (module.parent && module.parent.parent && module.parent.parent.filename) || __dirname); | ||
const log = (message = '', ...args) => { | ||
// tslint:disable-next-line strict-type-predicates | ||
message = typeof message === 'string' ? message : util_1.inspect(message); | ||
process.stdout.write(util_1.format(message, ...args) + '\n'); | ||
}; | ||
const helpOverride = (argv, config) => { | ||
if (argv.length === 0 && !config.pjson.oclif.default) | ||
return true; | ||
for (const arg of argv) { | ||
if (arg === '--help') | ||
return true; | ||
if (arg === '--') | ||
return false; | ||
} | ||
async init() { | ||
const [id, ...argv] = this.argv; | ||
await this.config.runHook('init', { id, argv }); | ||
return super.init(); | ||
return false; | ||
}; | ||
const versionOverride = (argv) => { | ||
if (['--version'].includes(argv[0])) | ||
return true; | ||
return false; | ||
}; | ||
async function run(argv = process.argv.slice(2), options) { | ||
// return Main.run(argv, options) | ||
const config = await config_1.Config.load(options || (module.parent && module.parent.parent && module.parent.parent.filename) || __dirname); | ||
// run init hook | ||
let [id, ...argvSlice] = argv; | ||
await config.runHook('init', { id, argv: argvSlice }); | ||
// display version if applicable | ||
if (versionOverride(argv)) { | ||
log(config.userAgent); | ||
return; | ||
} | ||
async run() { | ||
let [id, ...argv] = this.argv; | ||
this.parse(Object.assign({ strict: false, '--': false }, this.ctor)); | ||
if (!this.config.findCommand(id)) { | ||
const topic = this.config.findTopic(id); | ||
if (topic) | ||
return this._help(); | ||
if (this.config.findCommand(ROOT_INDEX_CMD_ID)) { | ||
id = ROOT_INDEX_CMD_ID; | ||
argv = this.argv; | ||
} | ||
} | ||
await this.config.runCommand(id, argv); | ||
} | ||
_helpOverride() { | ||
if (['-v', '--version', 'version'].includes(this.argv[0])) | ||
return this._version(); | ||
if (['-h', 'help'].includes(this.argv[0])) | ||
return true; | ||
if (this.argv.length === 0 && !this.config.findCommand(ROOT_INDEX_CMD_ID)) | ||
return true; | ||
for (const arg of this.argv) { | ||
// display help version if applicable | ||
if (helpOverride(argv, config)) { | ||
argv = argv.filter(arg => { | ||
if (arg === '--help') | ||
return true; | ||
if (arg === '--') | ||
return false; | ||
return true; | ||
}); | ||
const Help = help_1.getHelpClass(config); | ||
const help = new Help(config); | ||
help.showHelp(argv); | ||
return; | ||
} | ||
// find & run command | ||
if (!config.findCommand(id)) { | ||
const topic = config.findTopic(id); | ||
if (topic) | ||
return config.runCommand('help', [id]); | ||
if (config.pjson.oclif.default) { | ||
id = config.pjson.oclif.default; | ||
argvSlice = argv; | ||
} | ||
return false; | ||
} | ||
_help() { | ||
const HelpClass = help_1.getHelpClass(this.config); | ||
const help = new HelpClass(this.config); | ||
help.showHelp(this.argv); | ||
return this.exit(0); | ||
} | ||
await config.runCommand(id, argvSlice); | ||
} | ||
exports.Main = Main; | ||
function run(argv = process.argv.slice(2), options) { | ||
return Main.run(argv, options); | ||
} | ||
exports.run = run; |
@@ -6,3 +6,3 @@ "use strict"; | ||
return (options = {}) => { | ||
return Object.assign(Object.assign(Object.assign({ parse: (i, _) => i }, defaults), options), { input: [], multiple: Boolean(options.multiple), type: 'option' }); | ||
return Object.assign(Object.assign(Object.assign({ parse: async (i, _) => i }, defaults), options), { input: [], multiple: Boolean(options.multiple), type: 'option' }); | ||
}; | ||
@@ -12,7 +12,7 @@ } | ||
function boolean(options = {}) { | ||
return Object.assign(Object.assign({ parse: (b, _) => b }, options), { allowNo: Boolean(options.allowNo), type: 'boolean' }); | ||
return Object.assign(Object.assign({ parse: async (b, _) => b }, options), { allowNo: Boolean(options.allowNo), type: 'boolean' }); | ||
} | ||
exports.boolean = boolean; | ||
exports.integer = build({ | ||
parse: input => { | ||
parse: async (input) => { | ||
if (!/^-?\d+$/.test(input)) | ||
@@ -19,0 +19,0 @@ throw new Error(`Expected an integer but received: ${input}`); |
@@ -9,5 +9,5 @@ import * as args from './args'; | ||
[name: string]: string; | ||
}>(argv: string[], options: Input<TFlags>): ParserOutput<TFlags, TArgs>; | ||
}>(argv: string[], options: Input<TFlags>): Promise<ParserOutput<TFlags, TArgs>>; | ||
declare const boolean: typeof flags.boolean; | ||
declare const integer: import("../interfaces").Definition<number>; | ||
export { boolean, integer }; |
@@ -16,3 +16,3 @@ "use strict"; | ||
.add('validate', () => require('./validate').validate); | ||
function parse(argv, options) { | ||
async function parse(argv, options) { | ||
const input = { | ||
@@ -27,3 +27,3 @@ argv, | ||
const parser = new parse_1.Parser(input); | ||
const output = parser.parse(); | ||
const output = await parser.parse(); | ||
m.validate({ input, output }); | ||
@@ -30,0 +30,0 @@ return output; |
@@ -11,3 +11,3 @@ import { ParserInput, OutputFlags, ParsingToken, OutputArgs } from '../interfaces'; | ||
constructor(input: T); | ||
parse(): { | ||
parse(): Promise<{ | ||
args: TArgs; | ||
@@ -18,3 +18,3 @@ argv: any[]; | ||
metadata: any; | ||
}; | ||
}>; | ||
private _args; | ||
@@ -21,0 +21,0 @@ private _flags; |
"use strict"; | ||
// tslint:disable interface-over-type-literal | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const tslib_1 = require("tslib"); | ||
const deps_1 = require("./deps"); | ||
@@ -23,2 +24,25 @@ // eslint-disable-next-line new-cap | ||
} | ||
const readStdin = async () => { | ||
var e_1, _a; | ||
const { stdin } = process; | ||
let result; | ||
if (stdin.isTTY) | ||
return result; | ||
result = ''; | ||
stdin.setEncoding('utf8'); | ||
try { | ||
for (var stdin_1 = tslib_1.__asyncValues(stdin), stdin_1_1; stdin_1_1 = await stdin_1.next(), !stdin_1_1.done;) { | ||
const chunk = stdin_1_1.value; | ||
result += chunk; | ||
} | ||
} | ||
catch (e_1_1) { e_1 = { error: e_1_1 }; } | ||
finally { | ||
try { | ||
if (stdin_1_1 && !stdin_1_1.done && (_a = stdin_1.return)) await _a.call(stdin_1); | ||
} | ||
finally { if (e_1) throw e_1.error; } | ||
} | ||
return result; | ||
}; | ||
class Parser { | ||
@@ -35,3 +59,3 @@ constructor(input) { | ||
} | ||
parse() { | ||
async parse() { | ||
this._debugInput(); | ||
@@ -116,5 +140,5 @@ const findLongFlag = (arg) => { | ||
} | ||
const argv = this._argv(); | ||
const argv = await this._argv(); | ||
const args = this._args(argv); | ||
const flags = this._flags(); | ||
const flags = await this._flags(); | ||
this._debugOutput(argv, args, flags); | ||
@@ -137,3 +161,3 @@ return { | ||
} | ||
_flags() { | ||
async _flags() { | ||
const flags = {}; | ||
@@ -152,3 +176,4 @@ this.metaData.flags = {}; | ||
} | ||
flags[token.flag] = flag.parse(flags[token.flag], this.context); | ||
// eslint-disable-next-line no-await-in-loop | ||
flags[token.flag] = await flag.parse(flags[token.flag], this.context); | ||
} | ||
@@ -160,3 +185,4 @@ else { | ||
} | ||
const value = flag.parse ? flag.parse(input, this.context) : input; | ||
// eslint-disable-next-line no-await-in-loop | ||
const value = flag.parse ? await flag.parse(input, this.context) : input; | ||
if (flag.multiple) { | ||
@@ -177,4 +203,5 @@ flags[token.flag] = flags[token.flag] || []; | ||
const input = process.env[flag.env]; | ||
// eslint-disable-next-line no-await-in-loop | ||
if (input) | ||
flags[k] = flag.parse(input, this.context); | ||
flags[k] = await flag.parse(input, this.context); | ||
} | ||
@@ -184,3 +211,4 @@ if (!(k in flags) && flag.default !== undefined) { | ||
if (typeof flag.default === 'function') { | ||
flags[k] = flag.default(Object.assign({ options: flag, flags }, this.context)); | ||
// eslint-disable-next-line no-await-in-loop | ||
flags[k] = await flag.default(Object.assign({ options: flag, flags }, this.context)); | ||
} | ||
@@ -194,5 +222,6 @@ else { | ||
} | ||
_argv() { | ||
async _argv() { | ||
const args = []; | ||
const tokens = this._argTokens; | ||
let stdinRead = false; | ||
for (let i = 0; i < Math.max(this.input.args.length, tokens.length); i++) { | ||
@@ -206,3 +235,4 @@ const token = tokens[i]; | ||
} | ||
args[i] = arg.parse(token.input); | ||
// eslint-disable-next-line no-await-in-loop | ||
args[i] = await arg.parse(token.input); | ||
} | ||
@@ -213,5 +243,16 @@ else { | ||
} | ||
else if ('default' in arg) { | ||
else if (!arg.ignoreStdin && !stdinRead) { | ||
// eslint-disable-next-line no-await-in-loop | ||
let stdin = await readStdin(); | ||
if (stdin) { | ||
stdin = stdin.trim(); | ||
args[i] = stdin; | ||
} | ||
stdinRead = true; | ||
} | ||
if (!args[i] && 'default' in arg) { | ||
if (typeof arg.default === 'function') { | ||
args[i] = arg.default(); | ||
// eslint-disable-next-line no-await-in-loop | ||
const f = await arg.default(); | ||
args[i] = f; | ||
} | ||
@@ -218,0 +259,0 @@ else { |
{ | ||
"name": "@oclif/core", | ||
"description": "base library for oclif CLIs", | ||
"version": "0.2.0", | ||
"version": "0.3.0", | ||
"author": "Jeff Dickey @jdxcode", | ||
@@ -40,3 +40,3 @@ "bugs": "https://github.com/oclif/core/issues", | ||
"@types/node": "^14.0.14", | ||
"@types/node-notifier": "^6.0.1", | ||
"@types/node-notifier": "^8.0.0", | ||
"@types/proxyquire": "^1.3.28", | ||
@@ -80,3 +80,4 @@ "@types/read-pkg": "^5.1.0", | ||
"bin": "oclif", | ||
"plugins": [ | ||
"devPlugins": [ | ||
"@oclif/plugin-help", | ||
"@oclif/plugin-plugins" | ||
@@ -83,0 +84,0 @@ ] |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
144968
30
3939