@boost/cli
Advanced tools
Comparing version 1.1.0 to 1.2.0
@@ -6,2 +6,16 @@ # Change Log | ||
## 1.2.0 - 2020-04-29 | ||
#### 🚀 Updates | ||
- Add test utilities. (#77) ([f8d66ce](https://github.com/milesj/boost/commit/f8d66ce)), closes [#77](https://github.com/milesj/boost/issues/77) | ||
- Allow tasks to run other tasks. (#80) ([e08519f](https://github.com/milesj/boost/commit/e08519f)), closes [#80](https://github.com/milesj/boost/issues/80) | ||
- Buffer logs until rendering is complete. (#78) ([884a09a](https://github.com/milesj/boost/commit/884a09a)), closes [#78](https://github.com/milesj/boost/issues/78) | ||
**Note:** Version bump only for package @boost/cli | ||
## 1.1.0 - 2020-04-21 | ||
@@ -8,0 +22,0 @@ |
@@ -62,3 +62,3 @@ import React from 'react'; | ||
*/ | ||
runProgram(argv: Argv): Promise<void>; | ||
runProgram: (argv: Argv) => Promise<number>; | ||
/** | ||
@@ -68,3 +68,3 @@ * Run a task (function) with the defined arguments and | ||
*/ | ||
runTask<A extends unknown[], R>(task: (this: TaskContext<O>, ...args: A) => R, ...args: A): R; | ||
runTask: <A extends unknown[], R>(task: (this: TaskContext<O>, ...args: A) => R, ...args: A) => R; | ||
/** | ||
@@ -71,0 +71,0 @@ * Executed when the command is being ran. |
"use strict"; | ||
/* eslint-disable @typescript-eslint/consistent-type-assertions */ | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
@@ -39,2 +30,16 @@ return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
/** | ||
* Run the program within itself, by passing a custom command and argv list. | ||
*/ | ||
this.runProgram = (argv) => this.getProgram().run(argv, true); | ||
/** | ||
* Run a task (function) with the defined arguments and | ||
* the current command instance bound to the task's context. | ||
*/ | ||
this.runTask = (task, ...args) => { | ||
// We dont want tasks to have full access to the command | ||
// and its methods, so recreate a similar but smaller context. | ||
const context = Object.assign(Object.assign({ exit: this.exit, log: this.log, rest: this.rest, unknown: this.unknown }, this[constants_1.INTERNAL_OPTIONS]), { runProgram: this.runProgram, runTask: this.runTask }); | ||
return task.apply(context, args); | ||
}; | ||
/** | ||
* Verify sub-command is prefixed with the correct path. | ||
@@ -139,20 +144,2 @@ */ | ||
/** | ||
* Run the program within itself, by passing a custom command and argv list. | ||
*/ | ||
runProgram(argv) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
yield this.getProgram().run(argv, true); | ||
}); | ||
} | ||
/** | ||
* Run a task (function) with the defined arguments and | ||
* the current command instance bound to the task's context. | ||
*/ | ||
runTask(task, ...args) { | ||
// We dont want tasks to have full access to the command | ||
// and its methods, so recreate a similar but smaller context. | ||
const context = Object.assign({ exit: this.exit, log: this.log, rest: this.rest, unknown: this.unknown }, this[constants_1.INTERNAL_OPTIONS]); | ||
return task.apply(context, args); | ||
} | ||
/** | ||
* Return the program instance of fail. | ||
@@ -159,0 +146,0 @@ */ |
@@ -5,3 +5,3 @@ /** | ||
*/ | ||
import { Box, Color, Text, useInput, useStdin, useStdout, StdinProps, StdoutProps } from 'ink'; | ||
import { Box, Color, Text, Static, useInput, useStdin, useStdout, StdinProps, StdoutProps } from 'ink'; | ||
import Command from './Command'; | ||
@@ -19,4 +19,4 @@ import Failure from './Failure'; | ||
export * from './types'; | ||
export { Box, Color, Text, useInput, useStdin, useStdout, StdinProps, StdoutProps }; | ||
export { Box, Color, Text, Static, useInput, useStdin, useStdout, StdinProps, StdoutProps }; | ||
export { Command, Failure, Header, Help, IndexHelp, Program, ProgramContext, Style }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -17,2 +17,3 @@ "use strict"; | ||
exports.Text = ink_1.Text; | ||
exports.Static = ink_1.Static; | ||
exports.useInput = ink_1.useInput; | ||
@@ -19,0 +20,0 @@ exports.useStdin = ink_1.useStdin; |
/// <reference types="node" /> | ||
import { StreamType } from './types'; | ||
declare type BufferListener = (buffer: string[]) => void; | ||
declare type UnwrapHandler = () => void; | ||
export default class LogBuffer { | ||
logs: string[]; | ||
protected listener?: BufferListener; | ||
protected stream: NodeJS.WriteStream; | ||
protected timer?: NodeJS.Timeout; | ||
protected type: StreamType; | ||
@@ -15,4 +12,2 @@ protected unwrappers: UnwrapHandler[]; | ||
flush: () => void; | ||
off(): void; | ||
on(listener: BufferListener): void; | ||
unwrap(): void; | ||
@@ -19,0 +14,0 @@ wrap(): void; |
"use strict"; | ||
/* eslint-disable no-console */ | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const NOTIFY_DELAY = 150; | ||
const CONSOLE_METHODS = { | ||
stderr: [], | ||
stdout: [ | ||
'debug', | ||
'log', | ||
'info', | ||
// Until ink supports stderr | ||
'error', | ||
'trace', | ||
'warn', | ||
], | ||
stderr: ['error', 'trace', 'warn'], | ||
stdout: ['debug', 'log', 'info'], | ||
}; | ||
@@ -24,33 +15,16 @@ class LogBuffer { | ||
if (this.logs.length > 0) { | ||
if (this.listener) { | ||
this.listener(this.logs); | ||
} | ||
else { | ||
this.logs.forEach(this.writeToStream); | ||
} | ||
this.logs.forEach(this.writeToStream); | ||
this.logs = []; | ||
} | ||
if (this.timer) { | ||
clearTimeout(this.timer); | ||
delete this.timer; | ||
} | ||
}; | ||
this.write = (message) => { | ||
// `Static` will render each item in the array as a new line, | ||
// so trim surrounding new lines here | ||
const msg = typeof String.prototype.trimEnd === 'function' | ||
? String(message).trimEnd() | ||
: String(message).trim(); // Node 8 | ||
// If not wrapping the console, just output immediately | ||
if (!this.wrapped) { | ||
if (this.wrapped) { | ||
this.logs.push(msg); | ||
} | ||
else { | ||
this.writeToStream(msg); | ||
return; | ||
} | ||
// Static component will render each item in the array as a new line, | ||
// so trim surrounding new lines here | ||
this.logs.push(msg); | ||
// Place in a short timeout so that we can batch | ||
if (!this.timer) { | ||
this.timer = setTimeout(this.flush, NOTIFY_DELAY); | ||
} | ||
}; | ||
@@ -63,9 +37,2 @@ this.writeToStream = (message) => { | ||
} | ||
off() { | ||
this.flush(); | ||
delete this.listener; | ||
} | ||
on(listener) { | ||
this.listener = listener; | ||
} | ||
unwrap() { | ||
@@ -72,0 +39,0 @@ this.flush(); |
@@ -93,4 +93,3 @@ "use strict"; | ||
this.logger = log_1.createLogger({ | ||
// Use outBuffer until ink supports stderr | ||
stderr: this.outBuffer, | ||
stderr: this.errBuffer, | ||
stdout: this.outBuffer, | ||
@@ -100,2 +99,9 @@ }); | ||
this.onBeforeRegister.listen(this.handleBeforeRegister); | ||
// istanbul ignore next | ||
// if (process.env.NODE_ENV !== 'test') { | ||
// process.on('SIGINT', () => { | ||
// this.errBuffer.unwrap(); | ||
// this.outBuffer.unwrap(); | ||
// }); | ||
// } | ||
} | ||
@@ -270,3 +276,3 @@ blueprint({ string }) { | ||
this.rendering = true; | ||
yield ink_1.render(react_1.default.createElement(Wrapper_1.default, { errBuffer: this.errBuffer, exit: this.exit, logger: this.logger, outBuffer: this.outBuffer, program: this.options }, result || null), { | ||
const output = yield ink_1.render(react_1.default.createElement(Wrapper_1.default, { exit: this.exit, logger: this.logger, program: this.options }, result || null), { | ||
debug: process.env.NODE_ENV === 'test', | ||
@@ -277,3 +283,8 @@ exitOnCtrlC: true, | ||
stdout, | ||
}).waitUntilExit(); | ||
}); | ||
// This never resolves while testing | ||
// istanbul ignore next | ||
if (!internal_1.env('CLI_TEST_ONLY')) { | ||
yield output.waitUntilExit(); | ||
} | ||
this.rendering = false; | ||
@@ -300,3 +311,3 @@ this.onAfterRender.emit([]); | ||
// istanbul ignore next | ||
if (internal_1.env('CLI_FAIL_HARD')) { | ||
if (internal_1.env('CLI_TEST_FAIL_HARD')) { | ||
throw error; | ||
@@ -303,0 +314,0 @@ } |
@@ -5,3 +5,3 @@ /// <reference types="node" /> | ||
import { Logger } from '@boost/log'; | ||
export { ArgList, Arguments, Argv, Category, Flag, ListType, MultipleOption, Option, OptionConfig, OptionConfigMap, Param, ParamConfig, ParamConfigList, ParserOptions, PrimitiveType, ScalarType, SingleOption, ValueType, }; | ||
export { ArgList, Arguments, Argv, Category, Flag, ListType, MultipleOption, Option, OptionConfig, OptionConfigMap, Param, ParamConfig, ParamConfigList, ParserOptions, PrimitiveType, ScalarType, SingleOption, UnknownOptionMap, ValueType, }; | ||
export declare type PartialConfig<T> = Omit<T, 'default' | 'description' | 'multiple' | 'path' | 'type'>; | ||
@@ -83,2 +83,4 @@ export declare type Writeable<T> = { | ||
unknown: UnknownOptionMap; | ||
runProgram: (argv: Argv) => Promise<ExitCode>; | ||
runTask: <A extends unknown[], R>(task: (this: TaskContext<O>, ...args: A) => R, ...args: A) => R; | ||
}; | ||
@@ -85,0 +87,0 @@ export declare type MiddlewareArguments = Arguments<GlobalOptions, ArgList>; |
import React from 'react'; | ||
import { Logger } from '@boost/log'; | ||
import { ProgramOptions, ExitHandler } from './types'; | ||
import LogBuffer from './LogBuffer'; | ||
export interface WrapperProps { | ||
errBuffer: LogBuffer; | ||
exit: ExitHandler; | ||
logger: Logger; | ||
outBuffer: LogBuffer; | ||
program: ProgramOptions; | ||
} | ||
export interface WrapperState { | ||
errLogs: string[]; | ||
error: Error | null; | ||
outLogs: string[]; | ||
} | ||
export default class Wrapper extends React.Component<WrapperProps, WrapperState> { | ||
state: WrapperState; | ||
wrapped: { | ||
stderr: boolean; | ||
stdout: boolean; | ||
}; | ||
static getDerivedStateFromError(error: Error): { | ||
error: Error; | ||
}; | ||
componentDidMount(): void; | ||
componentWillUnmount(): void; | ||
render(): JSX.Element; | ||
} | ||
//# sourceMappingURL=Wrapper.d.ts.map |
@@ -14,10 +14,4 @@ "use strict"; | ||
this.state = { | ||
errLogs: [], | ||
error: null, | ||
outLogs: [], | ||
}; | ||
this.wrapped = { | ||
stderr: false, | ||
stdout: false, | ||
}; | ||
} | ||
@@ -27,27 +21,9 @@ static getDerivedStateFromError(error) { | ||
} | ||
componentDidMount() { | ||
this.props.errBuffer.on(errLogs => { | ||
this.setState(prev => ({ | ||
errLogs: prev.errLogs.concat(errLogs), | ||
})); | ||
}); | ||
this.props.outBuffer.on(outLogs => { | ||
this.setState(prev => ({ | ||
outLogs: prev.outLogs.concat(outLogs), | ||
})); | ||
}); | ||
} | ||
componentWillUnmount() { | ||
this.props.errBuffer.off(); | ||
this.props.outBuffer.off(); | ||
} | ||
render() { | ||
const { error, outLogs } = this.state; | ||
const { error } = this.state; | ||
const { children, exit, logger, program } = this.props; | ||
return (react_1.default.createElement(ink_1.Box, null, | ||
react_1.default.createElement(ProgramContext_1.default.Provider, { value: { exit, log: logger, program } }, | ||
react_1.default.createElement(ink_1.Static, null, outLogs), | ||
error ? (react_1.default.createElement(Failure_1.default, { binName: program.bin, delimiter: program.delimiter, error: error })) : (react_1.default.createElement(ink_1.Box, null, children))))); | ||
react_1.default.createElement(ProgramContext_1.default.Provider, { value: { exit, log: logger, program } }, error ? (react_1.default.createElement(Failure_1.default, { binName: program.bin, delimiter: program.delimiter, error: error })) : (children)))); | ||
} | ||
} | ||
exports.default = Wrapper; |
{ | ||
"name": "@boost/cli", | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"description": "A type-safe and interactive command line program, built on React and Ink.", | ||
@@ -27,9 +27,9 @@ "keywords": [ | ||
"dependencies": { | ||
"@boost/args": "^1.4.0", | ||
"@boost/common": "^1.8.4", | ||
"@boost/event": "^1.3.0", | ||
"@boost/internal": "^1.1.0", | ||
"@boost/log": "^1.1.14", | ||
"@boost/args": "^1.4.1", | ||
"@boost/common": "^1.8.5", | ||
"@boost/event": "^1.3.1", | ||
"@boost/internal": "^1.2.0", | ||
"@boost/log": "^1.2.0", | ||
"@boost/terminal": "^1.0.3", | ||
"@boost/translate": "^1.3.8", | ||
"@boost/translate": "^1.3.9", | ||
"execa": "^3.4.0", | ||
@@ -45,3 +45,3 @@ "ink": "^2.7.1", | ||
}, | ||
"gitHead": "69470850ecb8b5e73cc21ba573823f9102073487" | ||
"gitHead": "c77dc723462d054d8b7bbe927e99efd7e4f75084" | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
140344
148
2449
Updated@boost/args@^1.4.1
Updated@boost/common@^1.8.5
Updated@boost/event@^1.3.1
Updated@boost/internal@^1.2.0
Updated@boost/log@^1.2.0
Updated@boost/translate@^1.3.9