Skip to content

Commit

Permalink
feat: no longer use wrapped process.stdout and process.stderr
Browse files Browse the repository at this point in the history
  • Loading branch information
mdonnalley committed Oct 16, 2023
1 parent c2b9771 commit 3ff5f63
Show file tree
Hide file tree
Showing 15 changed files with 71 additions and 58 deletions.
21 changes: 10 additions & 11 deletions src/cli-ux/action/base.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {inspect} from 'node:util'

import {castArray} from '../../util/util'
import {stderr, stdout} from '../stream'
import {Options} from './types'

export interface ITask {
Expand All @@ -20,8 +19,8 @@ export class ActionBase {
type!: ActionType

private stdmockOrigs = {
stderr: stderr.write,
stdout: stdout.write,
stderr: process.stderr.write,
stdout: process.stdout.write,
}

protected get output(): string | undefined {
Expand Down Expand Up @@ -158,26 +157,26 @@ export class ActionBase {
if (toggle) {
if (this.stdmocks) return
this.stdmockOrigs = {
stderr: stderr.write,
stdout: stdout.write,
stderr: process.stderr.write,
stdout: process.stdout.write,
}

this.stdmocks = []
stdout.write = (...args: any[]) => {
process.stdout.write = (...args: any[]) => {
this.stdmocks!.push(['stdout', args] as ['stdout', string[]])
return true
}

stderr.write = (...args: any[]) => {
process.stderr.write = (...args: any[]) => {
this.stdmocks!.push(['stderr', args] as ['stderr', string[]])
return true
}
} else {
if (!this.stdmocks) return
// this._write('stderr', '\nresetstdmock\n\n\n')
delete this.stdmocks
stdout.write = this.stdmockOrigs.stdout
stderr.write = this.stdmockOrigs.stderr
process.stdout.write = this.stdmockOrigs.stdout
process.stderr.write = this.stdmockOrigs.stderr
}
} catch (error) {
this._write('stderr', inspect(error))
Expand All @@ -196,12 +195,12 @@ export class ActionBase {
protected _write(std: 'stderr' | 'stdout', s: string | string[]): void {
switch (std) {
case 'stdout': {
this.stdmockOrigs.stdout.apply(stdout, castArray(s) as [string])
this.stdmockOrigs.stdout.apply(process.stdout, castArray(s) as [string])
break
}

case 'stderr': {
this.stdmockOrigs.stderr.apply(stderr, castArray(s) as [string])
this.stdmockOrigs.stderr.apply(process.stderr, castArray(s) as [string])
break
}

Expand Down
5 changes: 2 additions & 3 deletions src/cli-ux/flush.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {error} from '../errors'
import {stdout} from './stream'

function timeout(p: Promise<any>, ms: number) {
function wait(ms: number, unref = false) {
Expand All @@ -14,9 +13,9 @@ function timeout(p: Promise<any>, ms: number) {

async function _flush() {
const p = new Promise((resolve) => {
stdout.once('drain', () => resolve(null))
process.stdout.once('drain', () => resolve(null))
})
const flushed = stdout.write('')
const flushed = process.stdout.write('')

if (flushed) return

Expand Down
20 changes: 13 additions & 7 deletions src/cli-ux/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ import {format as utilFormat} from 'node:util'

import * as Errors from '../errors'
import {ActionBase} from './action/base'
import {Config, config} from './config'
import {config} from './config'
import {flush as _flush} from './flush'
import * as uxPrompt from './prompt'
import {stdout} from './stream'
import * as styled from './styled'
import uxWait from './wait'
import write from './write'

const hyperlinker = require('hyperlinker')

export class ux {
public static config: Config = config
public static config = config

public static get action(): ActionBase {
return config.action
Expand Down Expand Up @@ -42,7 +42,7 @@ export class ux {

public static debug(format: string, ...args: string[]): void {
if (['debug', 'trace'].includes(this.config.outputLevel)) {
stdout.write(utilFormat(format, ...args) + '\n')
this.info(utilFormat(format, ...args) + '\n')
}
}

Expand All @@ -55,13 +55,17 @@ export class ux {
}

public static info(format: string, ...args: string[]): void {
stdout.write(utilFormat(format, ...args) + '\n')
write.stdout(utilFormat(format, ...args) + '\n')
}

public static log(format?: string, ...args: string[]): void {
this.info(format || '', ...args)
}

public static logToStderr(format?: string, ...args: string[]): void {
write.stderr(utilFormat(format, ...args) + '\n')
}

public static get progress(): typeof styled.progress {
return styled.progress
}
Expand All @@ -77,7 +81,7 @@ export class ux {
public static styledJSON(obj: unknown): void {
const json = JSON.stringify(obj, null, 2)
if (!chalk.level) {
info(json)
this.info(json)
return
}

Expand All @@ -96,7 +100,7 @@ export class ux {

public static trace(format: string, ...args: string[]): void {
if (this.config.outputLevel === 'trace') {
stdout.write(utilFormat(format, ...args) + '\n')
this.info(utilFormat(format, ...args) + '\n')
}
}

Expand Down Expand Up @@ -128,6 +132,7 @@ const {
flush,
info,
log,
logToStderr,
progress,
prompt,
styledHeader,
Expand All @@ -153,6 +158,7 @@ export {
flush,
info,
log,
logToStderr,
progress,
prompt,
styledHeader,
Expand Down
7 changes: 3 additions & 4 deletions src/cli-ux/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import chalk from 'chalk'

import * as Errors from '../errors'
import {config} from './config'
import {stderr} from './stream'

export interface IPromptOptions {
default?: string
Expand Down Expand Up @@ -38,7 +37,7 @@ function normal(options: IPromptConfig, retries = 100): Promise<string> {
}

process.stdin.setEncoding('utf8')
stderr.write(options.prompt)
process.stderr.write(options.prompt)
process.stdin.resume()
process.stdin.once('data', (b) => {
if (timer) clearTimeout(timer)
Expand Down Expand Up @@ -77,7 +76,7 @@ async function single(options: IPromptConfig): Promise<string> {

function replacePrompt(prompt: string) {
const ansiEscapes = require('ansi-escapes')
stderr.write(
process.stderr.write(
ansiEscapes.cursorHide +
ansiEscapes.cursorUp(1) +
ansiEscapes.cursorLeft +
Expand Down Expand Up @@ -178,7 +177,7 @@ export async function anykey(message?: string): Promise<string> {
}

const char = await prompt(message, {required: false, type: 'single'})
if (tty) stderr.write('\n')
if (tty) process.stderr.write('\n')
if (char === 'q') Errors.error('quit')
if (char === '\u0003') Errors.error('ctrl-c')
return char
Expand Down
6 changes: 6 additions & 0 deletions src/cli-ux/stream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,11 @@ class Stream {
}
}

/**
* @deprecated Use process.stdout directly. This will be removed in the next major version
*/
export const stdout = new Stream('stdout')
/**
* @deprecated Use process.stderr directly. This will be removed in the next major version
*/
export const stderr = new Stream('stderr')
8 changes: 4 additions & 4 deletions src/cli-ux/styled/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import * as F from '../../flags'
import * as Interfaces from '../../interfaces'
import {stdtermwidth} from '../../screen'
import {capitalize, sumBy} from '../../util/util'
import {stdout} from '../stream'
import write from '../write'

class Table<T extends Record<string, unknown>> {
columns: (table.Column<T> & {key: string; maxWidth?: number; width?: number})[]
Expand Down Expand Up @@ -48,7 +48,7 @@ class Table<T extends Record<string, unknown>> {
'no-header': options['no-header'] ?? false,
'no-truncate': options['no-truncate'] ?? false,
output: csv ? 'csv' : output,
printLine: printLine ?? ((s: any) => stdout.write(s + '\n')),
printLine: printLine ?? ((s: any) => write.stdout(s + '\n')),
rowStart: ' ',
sort,
title,
Expand Down Expand Up @@ -97,7 +97,7 @@ class Table<T extends Record<string, unknown>> {
const filters = this.options.columns!.split(',')
this.columns = this.filterColumnsFromHeaders(filters)
} else if (!this.options.extended) {
// show extented columns/properties
// show extended columns/properties
this.columns = this.columns.filter((c) => !c.extended)
}

Expand Down Expand Up @@ -189,7 +189,7 @@ class Table<T extends Record<string, unknown>> {
// truncation logic
const shouldShorten = () => {
// don't shorten if full mode
if (options['no-truncate'] || (!stdout.isTTY && !process.env.CLI_UX_SKIP_TTY_CHECK)) return
if (options['no-truncate'] || (!process.stdout.isTTY && !process.env.CLI_UX_SKIP_TTY_CHECK)) return

// don't shorten if there is enough screen width
const dataMaxWidth = sumBy(columns, (c) => c.width!)
Expand Down
12 changes: 12 additions & 0 deletions src/cli-ux/write.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const stdout = (msg: string): void => {
process.stdout.write(msg)
}

const stderr = (msg: string): void => {
process.stderr.write(msg)
}

export default {
stderr,
stdout,
}
9 changes: 4 additions & 5 deletions src/command.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import chalk from 'chalk'
import {fileURLToPath} from 'node:url'
import {format, inspect} from 'node:util'
import {inspect} from 'node:util'

import {ux} from './cli-ux'
import {stderr, stdout} from './cli-ux/stream'
import {Config} from './config'
import * as Errors from './errors'
import {PrettyPrintableError} from './errors'
Expand Down Expand Up @@ -37,7 +36,7 @@ const pjson = requireJson<PJSON>(__dirname, '..', 'package.json')
* swallows stdout epipe errors
* this occurs when stdout closes such as when piping to head
*/
stdout.on('error', (err: any) => {
process.stdout.on('error', (err: any) => {
if (err && err.code === 'EPIPE') return
throw err
})
Expand Down Expand Up @@ -258,7 +257,7 @@ export abstract class Command {
public log(message = '', ...args: any[]): void {
if (!this.jsonEnabled()) {
message = typeof message === 'string' ? message : inspect(message)
stdout.write(format(message, ...args) + '\n')
ux.info(message, ...args)
}
}

Expand All @@ -269,7 +268,7 @@ export abstract class Command {
public logToStderr(message = '', ...args: any[]): void {
if (!this.jsonEnabled()) {
message = typeof message === 'string' ? message : inspect(message)
stderr.write(format(message, ...args) + '\n')
ux.logToStderr(message, ...args)
}
}

Expand Down
5 changes: 2 additions & 3 deletions src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ import WSL from 'is-wsl'
import {arch, userInfo as osUserInfo, release, tmpdir, type} from 'node:os'
import {join, sep} from 'node:path'
import {URL, fileURLToPath} from 'node:url'
import {format} from 'node:util'

import {stdout} from '../cli-ux/stream'
import {ux} from '../cli-ux'
import {Command} from '../command'
import {CLIError, error, exit, warn} from '../errors'
import {getHelpFlagAdditions} from '../help/util'
Expand Down Expand Up @@ -499,7 +498,7 @@ export class Config implements IConfig {
exit(code)
},
log(message?: any, ...args: any[]) {
stdout.write(format(message, ...args) + '\n')
ux.info(message, ...args)
},
warn(message: string) {
warn(message)
Expand Down
6 changes: 3 additions & 3 deletions src/help/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {format} from 'node:util'
import stripAnsi from 'strip-ansi'

import {stdout} from '../cli-ux/stream'
import write from '../cli-ux/write'
import {Command} from '../command'
import {error} from '../errors'
import * as Interfaces from '../interfaces'
Expand Down Expand Up @@ -155,8 +155,8 @@ export class Help extends HelpBase {
return new this.CommandHelpClass(command, this.config, this.opts)
}

protected log(...args: string[]): void {
stdout.write(format.apply(this, args) + '\n')
protected log(...args: string[]) {
write.stdout(format.apply(this, args) + '\n')
}

public async showCommandHelp(command: Command.Loadable): Promise<void> {
Expand Down
5 changes: 3 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import {stderr} from './cli-ux/stream'
import write from './cli-ux/write'

function checkCWD() {
try {
process.cwd()
} catch (error: any) {
if (error.code === 'ENOENT') {
stderr.write('WARNING: current directory does not exist\n')
write.stderr('WARNING: current directory does not exist\n')
}
}
}
Expand All @@ -15,6 +15,7 @@ checkCWD()
export * as Args from './args'
export * as ux from './cli-ux'
export {flush} from './cli-ux/flush'
// Remove these in the next major version
export {stderr, stdout} from './cli-ux/stream'
export {Command} from './command'
export {Config, Plugin} from './config'
Expand Down
10 changes: 2 additions & 8 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
import {URL, fileURLToPath} from 'node:url'
import {format, inspect} from 'node:util'

import {stdout} from './cli-ux/stream'
import {ux} from './cli-ux'
import {Config} from './config'
import {getHelpFlagAdditions, loadHelpClass, normalizeArgv} from './help'
import * as Interfaces from './interfaces'
import {OCLIF_MARKER_OWNER, Performance} from './performance'

const debug = require('debug')('oclif:main')

const log = (message = '', ...args: any[]) => {
message = typeof message === 'string' ? message : inspect(message)
stdout.write(format(message, ...args) + '\n')
}

export const helpAddition = (argv: string[], config: Interfaces.Config): boolean => {
if (argv.length === 0 && !config.pjson.oclif.default) return true
const mergedHelpFlags = getHelpFlagAdditions(config)
Expand Down Expand Up @@ -62,7 +56,7 @@ export async function run(argv?: string[], options?: Interfaces.LoadOptions): Pr

// display version if applicable
if (versionAddition(argv, config)) {
log(config.userAgent)
ux.log(config.userAgent)
await collectPerf()
return
}
Expand Down
Loading

0 comments on commit 3ff5f63

Please sign in to comment.