Comparing version 9.2.0 to 9.3.0
@@ -27,1 +27,2 @@ export type { | ||
} from './types/ipc.js'; | ||
export type {VerboseObject, SyncVerboseObject} from './types/verbose.js'; |
@@ -11,4 +11,5 @@ import {logCommand} from '../verbose/start.js'; | ||
const {command, escapedCommand} = joinCommand(filePath, rawArguments); | ||
const verboseInfo = getVerboseInfo(normalizeFdSpecificOption(rawOptions, 'verbose')); | ||
logCommand(escapedCommand, verboseInfo, rawOptions); | ||
const verbose = normalizeFdSpecificOption(rawOptions, 'verbose'); | ||
const verboseInfo = getVerboseInfo(verbose, escapedCommand, {...rawOptions}); | ||
logCommand(escapedCommand, verboseInfo); | ||
return { | ||
@@ -15,0 +16,0 @@ command, |
@@ -0,4 +1,4 @@ | ||
import {debuglog} from 'node:util'; | ||
import isPlainObject from 'is-plain-obj'; | ||
import {STANDARD_STREAMS_ALIASES} from '../utils/standard-stream.js'; | ||
import {verboseDefault} from '../verbose/info.js'; | ||
@@ -94,2 +94,5 @@ // Some options can have different values for `stdout`/`stderr`/`fd3`. | ||
// Default value for the `verbose` option | ||
const verboseDefault = debuglog('execa').enabled ? 'full' : 'none'; | ||
const DEFAULT_OPTIONS = { | ||
@@ -105,1 +108,6 @@ lines: false, | ||
export const FD_SPECIFIC_OPTIONS = ['lines', 'buffer', 'maxBuffer', 'verbose', 'stripFinalNewline']; | ||
// Retrieve fd-specific option | ||
export const getFdSpecificValue = (optionArray, fdNumber) => fdNumber === 'ipc' | ||
? optionArray.at(-1) | ||
: optionArray[fdNumber]; |
@@ -10,22 +10,15 @@ import {setImmediate} from 'node:timers/promises'; | ||
// Retrieve `result.stdout|stderr|all|stdio[*]` | ||
export const getStreamOutput = async ({stream, onStreamEnd, fdNumber, encoding, buffer, maxBuffer, lines, allMixed, stripFinalNewline, verboseInfo, streamInfo: {fileDescriptors}}) => { | ||
if (shouldLogOutput({ | ||
stdioItems: fileDescriptors[fdNumber]?.stdioItems, | ||
export const getStreamOutput = async ({stream, onStreamEnd, fdNumber, encoding, buffer, maxBuffer, lines, allMixed, stripFinalNewline, verboseInfo, streamInfo}) => { | ||
const logPromise = logOutputAsync({ | ||
stream, | ||
onStreamEnd, | ||
fdNumber, | ||
encoding, | ||
allMixed, | ||
verboseInfo, | ||
fdNumber, | ||
})) { | ||
const linesIterable = iterateForResult({ | ||
stream, | ||
onStreamEnd, | ||
lines: true, | ||
encoding, | ||
stripFinalNewline: true, | ||
allMixed, | ||
}); | ||
logLines(linesIterable, stream, verboseInfo); | ||
} | ||
streamInfo, | ||
}); | ||
if (!buffer) { | ||
await resumeStream(stream); | ||
await Promise.all([resumeStream(stream), logPromise]); | ||
return; | ||
@@ -43,10 +36,35 @@ } | ||
}); | ||
return getStreamContents({ | ||
const [output] = await Promise.all([ | ||
getStreamContents({ | ||
stream, | ||
iterable, | ||
fdNumber, | ||
encoding, | ||
maxBuffer, | ||
lines, | ||
}), | ||
logPromise, | ||
]); | ||
return output; | ||
}; | ||
const logOutputAsync = async ({stream, onStreamEnd, fdNumber, encoding, allMixed, verboseInfo, streamInfo: {fileDescriptors}}) => { | ||
if (!shouldLogOutput({ | ||
stdioItems: fileDescriptors[fdNumber]?.stdioItems, | ||
encoding, | ||
verboseInfo, | ||
fdNumber, | ||
})) { | ||
return; | ||
} | ||
const linesIterable = iterateForResult({ | ||
stream, | ||
iterable, | ||
fdNumber, | ||
onStreamEnd, | ||
lines: true, | ||
encoding, | ||
maxBuffer, | ||
lines, | ||
stripFinalNewline: true, | ||
allMixed, | ||
}); | ||
await logLines(linesIterable, stream, fdNumber, verboseInfo); | ||
}; | ||
@@ -53,0 +71,0 @@ |
import {MaxBufferError} from 'get-stream'; | ||
import {getStreamName} from '../utils/standard-stream.js'; | ||
import {getFdSpecificValue} from '../arguments/specific.js'; | ||
@@ -62,7 +63,8 @@ // When the `maxBuffer` option is hit, a MaxBufferError is thrown. | ||
const threshold = getFdSpecificValue(maxBuffer, fdNumber); | ||
if (fdNumber === 'ipc') { | ||
return {streamName: 'IPC output', threshold: maxBuffer.at(-1), unit: 'messages'}; | ||
return {streamName: 'IPC output', threshold, unit: 'messages'}; | ||
} | ||
return {streamName: getStreamName(fdNumber), threshold: maxBuffer[fdNumber], unit}; | ||
return {streamName: getStreamName(fdNumber), threshold, unit}; | ||
}; | ||
@@ -69,0 +71,0 @@ |
@@ -51,11 +51,11 @@ import {writeFileSync, appendFileSync} from 'node:fs'; | ||
if (shouldLogOutput({ | ||
logOutputSync({ | ||
serializedResult, | ||
fdNumber, | ||
state, | ||
verboseInfo, | ||
encoding, | ||
stdioItems, | ||
encoding, | ||
verboseInfo, | ||
fdNumber, | ||
})) { | ||
const linesArray = splitLinesSync(serializedResult, false, objectMode); | ||
logLinesSync(linesArray, verboseInfo); | ||
} | ||
objectMode, | ||
}); | ||
@@ -106,2 +106,21 @@ const returnedResult = buffer[fdNumber] ? finalResult : undefined; | ||
const logOutputSync = ({serializedResult, fdNumber, state, verboseInfo, encoding, stdioItems, objectMode}) => { | ||
if (!shouldLogOutput({ | ||
stdioItems, | ||
encoding, | ||
verboseInfo, | ||
fdNumber, | ||
})) { | ||
return; | ||
} | ||
const linesArray = splitLinesSync(serializedResult, false, objectMode); | ||
try { | ||
logLinesSync(linesArray, fdNumber, verboseInfo); | ||
} catch (error) { | ||
state.error ??= error; | ||
} | ||
}; | ||
// When the `std*` target is a file path/URL or a file descriptor | ||
@@ -108,0 +127,0 @@ const writeToFiles = (serializedResult, stdioItems, outputFiles) => { |
import {checkIpcMaxBuffer} from '../io/max-buffer.js'; | ||
import {shouldLogIpc, logIpcOutput} from '../verbose/ipc.js'; | ||
import {getFdSpecificValue} from '../arguments/specific.js'; | ||
import {loopOnMessages} from './get-each.js'; | ||
@@ -19,4 +20,4 @@ | ||
const isVerbose = shouldLogIpc(verboseInfo); | ||
const buffer = bufferArray.at(-1); | ||
const maxBuffer = maxBufferArray.at(-1); | ||
const buffer = getFdSpecificValue(bufferArray, 'ipc'); | ||
const maxBuffer = getFdSpecificValue(maxBufferArray, 'ipc'); | ||
@@ -23,0 +24,0 @@ for await (const message of loopOnMessages({ |
import {createDeferred} from '../utils/deferred.js'; | ||
import {getFdSpecificValue} from '../arguments/specific.js'; | ||
import {SUBPROCESS_OPTIONS} from '../arguments/fd-options.js'; | ||
@@ -44,4 +45,4 @@ import {validateStrictDeadlock} from './strict.js'; | ||
const getMinListenerCount = anyProcess => SUBPROCESS_OPTIONS.has(anyProcess) | ||
&& !SUBPROCESS_OPTIONS.get(anyProcess).options.buffer.at(-1) | ||
&& !getFdSpecificValue(SUBPROCESS_OPTIONS.get(anyProcess).options.buffer, 'ipc') | ||
? 1 | ||
: 0; |
@@ -17,3 +17,2 @@ import {setMaxListeners} from 'node:events'; | ||
import {pipeToSubprocess} from '../pipe/setup.js'; | ||
import {logEarlyResult} from '../verbose/complete.js'; | ||
import {makeAllStream} from '../resolve/all-async.js'; | ||
@@ -52,21 +51,15 @@ import {waitForSubprocessResult} from '../resolve/wait-subprocess.js'; | ||
const {command, escapedCommand, startTime, verboseInfo} = handleCommand(rawFile, rawArguments, rawOptions); | ||
try { | ||
const {file, commandArguments, options: normalizedOptions} = normalizeOptions(rawFile, rawArguments, rawOptions); | ||
const options = handleAsyncOptions(normalizedOptions); | ||
const fileDescriptors = handleStdioAsync(options, verboseInfo); | ||
return { | ||
file, | ||
commandArguments, | ||
command, | ||
escapedCommand, | ||
startTime, | ||
verboseInfo, | ||
options, | ||
fileDescriptors, | ||
}; | ||
} catch (error) { | ||
logEarlyResult(error, startTime, verboseInfo); | ||
throw error; | ||
} | ||
const {file, commandArguments, options: normalizedOptions} = normalizeOptions(rawFile, rawArguments, rawOptions); | ||
const options = handleAsyncOptions(normalizedOptions); | ||
const fileDescriptors = handleStdioAsync(options, verboseInfo); | ||
return { | ||
file, | ||
commandArguments, | ||
command, | ||
escapedCommand, | ||
startTime, | ||
verboseInfo, | ||
options, | ||
fileDescriptors, | ||
}; | ||
}; | ||
@@ -73,0 +66,0 @@ |
@@ -11,3 +11,2 @@ import {spawnSync} from 'node:child_process'; | ||
import {getMaxBufferSync} from '../io/max-buffer.js'; | ||
import {logEarlyResult} from '../verbose/complete.js'; | ||
import {getAllSync} from '../resolve/all-sync.js'; | ||
@@ -35,22 +34,16 @@ import {getExitResultSync} from '../resolve/exit-sync.js'; | ||
const {command, escapedCommand, startTime, verboseInfo} = handleCommand(rawFile, rawArguments, rawOptions); | ||
try { | ||
const syncOptions = normalizeSyncOptions(rawOptions); | ||
const {file, commandArguments, options} = normalizeOptions(rawFile, rawArguments, syncOptions); | ||
validateSyncOptions(options); | ||
const fileDescriptors = handleStdioSync(options, verboseInfo); | ||
return { | ||
file, | ||
commandArguments, | ||
command, | ||
escapedCommand, | ||
startTime, | ||
verboseInfo, | ||
options, | ||
fileDescriptors, | ||
}; | ||
} catch (error) { | ||
logEarlyResult(error, startTime, verboseInfo); | ||
throw error; | ||
} | ||
const syncOptions = normalizeSyncOptions(rawOptions); | ||
const {file, commandArguments, options} = normalizeOptions(rawFile, rawArguments, syncOptions); | ||
validateSyncOptions(options); | ||
const fileDescriptors = handleStdioSync(options, verboseInfo); | ||
return { | ||
file, | ||
commandArguments, | ||
command, | ||
escapedCommand, | ||
startTime, | ||
verboseInfo, | ||
options, | ||
fileDescriptors, | ||
}; | ||
}; | ||
@@ -57,0 +50,0 @@ |
@@ -1,2 +0,2 @@ | ||
import {logFinalResult} from '../verbose/complete.js'; | ||
import {logResult} from '../verbose/complete.js'; | ||
@@ -6,3 +6,3 @@ // Applies the `reject` option. | ||
export const handleResult = (result, verboseInfo, {reject}) => { | ||
logFinalResult(result, reject, verboseInfo); | ||
logResult(result, verboseInfo); | ||
@@ -9,0 +9,0 @@ if (result.failed && reject) { |
@@ -20,3 +20,3 @@ import {getStreamName, isStandardStream} from '../utils/standard-stream.js'; | ||
export const handleStdio = (addProperties, options, verboseInfo, isSync) => { | ||
const stdio = normalizeStdioOption(options, isSync); | ||
const stdio = normalizeStdioOption(options, verboseInfo, isSync); | ||
const initialFileDescriptors = stdio.map((stdioOption, fdNumber) => getFileDescriptor({ | ||
@@ -23,0 +23,0 @@ stdioOption, |
import {STANDARD_STREAMS_ALIASES} from '../utils/standard-stream.js'; | ||
import {normalizeIpcStdioArray} from '../ipc/array.js'; | ||
import {isFullVerbose} from '../verbose/values.js'; | ||
// Add support for `stdin`/`stdout`/`stderr` as an alias for `stdio`. | ||
// Also normalize the `stdio` option. | ||
export const normalizeStdioOption = ({stdio, ipc, buffer, verbose, ...options}, isSync) => { | ||
export const normalizeStdioOption = ({stdio, ipc, buffer, ...options}, verboseInfo, isSync) => { | ||
const stdioArray = getStdioArray(stdio, options).map((stdioOption, fdNumber) => addDefaultValue(stdioOption, fdNumber)); | ||
return isSync | ||
? normalizeStdioSync(stdioArray, buffer, verbose) | ||
? normalizeStdioSync(stdioArray, buffer, verboseInfo) | ||
: normalizeIpcStdioArray(stdioArray, ipc); | ||
@@ -50,6 +51,6 @@ }; | ||
// Unless the output is needed, e.g. due to `verbose: 'full'` or to redirecting to a file. | ||
const normalizeStdioSync = (stdioArray, buffer, verbose) => stdioArray.map((stdioOption, fdNumber) => | ||
const normalizeStdioSync = (stdioArray, buffer, verboseInfo) => stdioArray.map((stdioOption, fdNumber) => | ||
!buffer[fdNumber] | ||
&& fdNumber !== 0 | ||
&& verbose[fdNumber] !== 'full' | ||
&& !isFullVerbose(verboseInfo, fdNumber) | ||
&& isOutputPipeOnly(stdioOption) | ||
@@ -56,0 +57,0 @@ ? 'ignore' |
import prettyMs from 'pretty-ms'; | ||
import {gray} from 'yoctocolors'; | ||
import {escapeLines} from '../arguments/escape.js'; | ||
import {getDurationMs} from '../return/duration.js'; | ||
import {isVerbose} from './info.js'; | ||
import {isVerbose} from './values.js'; | ||
import {verboseLog} from './log.js'; | ||
import {logError} from './error.js'; | ||
// When `verbose` is `short|full`, print each command's completion, duration and error | ||
export const logFinalResult = ({shortMessage, failed, durationMs}, reject, verboseInfo) => { | ||
logResult({ | ||
message: shortMessage, | ||
failed, | ||
reject, | ||
durationMs, | ||
verboseInfo, | ||
}); | ||
}; | ||
// Same but for early validation errors | ||
export const logEarlyResult = (error, startTime, verboseInfo) => { | ||
logResult({ | ||
message: escapeLines(String(error)), | ||
failed: true, | ||
reject: true, | ||
durationMs: getDurationMs(startTime), | ||
verboseInfo, | ||
}); | ||
}; | ||
const logResult = ({message, failed, reject, durationMs, verboseInfo: {verbose, verboseId}}) => { | ||
if (!isVerbose(verbose)) { | ||
// When `verbose` is `short|full|custom`, print each command's completion, duration and error | ||
export const logResult = (result, verboseInfo) => { | ||
if (!isVerbose(verboseInfo)) { | ||
return; | ||
} | ||
const icon = getIcon(failed, reject); | ||
logError({ | ||
message, | ||
failed, | ||
reject, | ||
verboseId, | ||
icon, | ||
}); | ||
logDuration(durationMs, verboseId, icon); | ||
logError(result, verboseInfo); | ||
logDuration(result, verboseInfo); | ||
}; | ||
const logDuration = (durationMs, verboseId, icon) => { | ||
const durationMessage = `(done in ${prettyMs(durationMs)})`; | ||
verboseLog(durationMessage, verboseId, icon, gray); | ||
const logDuration = (result, verboseInfo) => { | ||
const verboseMessage = `(done in ${prettyMs(result.durationMs)})`; | ||
verboseLog({ | ||
type: 'duration', | ||
verboseMessage, | ||
verboseInfo, | ||
result, | ||
}); | ||
}; | ||
const getIcon = (failed, reject) => { | ||
if (!failed) { | ||
return 'success'; | ||
} | ||
return reject ? 'error' : 'warning'; | ||
}; |
@@ -1,12 +0,13 @@ | ||
import {redBright, yellowBright} from 'yoctocolors'; | ||
import {verboseLog} from './log.js'; | ||
// When `verbose` is `short|full`, print each command's error when it fails | ||
export const logError = ({message, failed, reject, verboseId, icon}) => { | ||
if (!failed) { | ||
return; | ||
// When `verbose` is `short|full|custom`, print each command's error when it fails | ||
export const logError = (result, verboseInfo) => { | ||
if (result.failed) { | ||
verboseLog({ | ||
type: 'error', | ||
verboseMessage: result.shortMessage, | ||
verboseInfo, | ||
result, | ||
}); | ||
} | ||
const color = reject ? redBright : yellowBright; | ||
verboseLog(message, verboseId, icon, color); | ||
}; |
@@ -1,13 +0,17 @@ | ||
import {debuglog} from 'node:util'; | ||
import {isVerbose, VERBOSE_VALUES, isVerboseFunction} from './values.js'; | ||
// Default value for the `verbose` option | ||
export const verboseDefault = debuglog('execa').enabled ? 'full' : 'none'; | ||
// Information computed before spawning, used by the `verbose` option | ||
export const getVerboseInfo = verbose => { | ||
const verboseId = isVerbose(verbose) ? VERBOSE_ID++ : undefined; | ||
export const getVerboseInfo = (verbose, escapedCommand, rawOptions) => { | ||
validateVerbose(verbose); | ||
return {verbose, verboseId}; | ||
const commandId = getCommandId(verbose); | ||
return { | ||
verbose, | ||
escapedCommand, | ||
commandId, | ||
rawOptions, | ||
}; | ||
}; | ||
const getCommandId = verbose => isVerbose({verbose}) ? COMMAND_ID++ : undefined; | ||
// Prepending the `pid` is useful when multiple commands print their output at the same time. | ||
@@ -18,24 +22,19 @@ // However, we cannot use the real PID since this is not available with `child_process.spawnSync()`. | ||
// As a con, it cannot be used to send signals. | ||
let VERBOSE_ID = 0n; | ||
let COMMAND_ID = 0n; | ||
// The `verbose` option can have different values for `stdout`/`stderr` | ||
export const isVerbose = verbose => verbose.some(fdVerbose => fdVerbose !== 'none'); | ||
const validateVerbose = verbose => { | ||
for (const verboseItem of verbose) { | ||
if (verboseItem === false) { | ||
for (const fdVerbose of verbose) { | ||
if (fdVerbose === false) { | ||
throw new TypeError('The "verbose: false" option was renamed to "verbose: \'none\'".'); | ||
} | ||
if (verboseItem === true) { | ||
if (fdVerbose === true) { | ||
throw new TypeError('The "verbose: true" option was renamed to "verbose: \'short\'".'); | ||
} | ||
if (!VERBOSE_VALUES.has(verboseItem)) { | ||
const allowedValues = [...VERBOSE_VALUES].map(allowedValue => `'${allowedValue}'`).join(', '); | ||
throw new TypeError(`The "verbose" option must not be ${verboseItem}. Allowed values are: ${allowedValues}.`); | ||
if (!VERBOSE_VALUES.includes(fdVerbose) && !isVerboseFunction(fdVerbose)) { | ||
const allowedValues = VERBOSE_VALUES.map(allowedValue => `'${allowedValue}'`).join(', '); | ||
throw new TypeError(`The "verbose" option must not be ${fdVerbose}. Allowed values are: ${allowedValues} or a function.`); | ||
} | ||
} | ||
}; | ||
const VERBOSE_VALUES = new Set(['none', 'short', 'full']); |
@@ -1,8 +0,15 @@ | ||
import {verboseLog, serializeLogMessage} from './log.js'; | ||
import {verboseLog, serializeVerboseMessage} from './log.js'; | ||
import {isFullVerbose} from './values.js'; | ||
// When `verbose` is `'full'`, print IPC messages from the subprocess | ||
export const shouldLogIpc = ({verbose}) => verbose.at(-1) === 'full'; | ||
export const shouldLogIpc = verboseInfo => isFullVerbose(verboseInfo, 'ipc'); | ||
export const logIpcOutput = (message, {verboseId}) => { | ||
verboseLog(serializeLogMessage(message), verboseId, 'ipc'); | ||
export const logIpcOutput = (message, verboseInfo) => { | ||
const verboseMessage = serializeVerboseMessage(message); | ||
verboseLog({ | ||
type: 'ipc', | ||
verboseMessage, | ||
fdNumber: 'ipc', | ||
verboseInfo, | ||
}); | ||
}; |
import {writeFileSync} from 'node:fs'; | ||
import {inspect} from 'node:util'; | ||
import figures from 'figures'; | ||
import {gray} from 'yoctocolors'; | ||
import {escapeLines} from '../arguments/escape.js'; | ||
import {defaultVerboseFunction} from './default.js'; | ||
import {applyVerboseOnLines} from './custom.js'; | ||
// Write synchronously to ensure lines are properly ordered and not interleaved with `stdout` | ||
export const verboseLog = (string, verboseId, icon, color) => { | ||
const prefixedLines = addPrefix(string, verboseId, icon, color); | ||
writeFileSync(STDERR_FD, `${prefixedLines}\n`); | ||
export const verboseLog = ({type, verboseMessage, fdNumber, verboseInfo, result}) => { | ||
const verboseObject = getVerboseObject({type, result, verboseInfo}); | ||
const printedLines = getPrintedLines(verboseMessage, verboseObject); | ||
const finalLines = applyVerboseOnLines(printedLines, verboseInfo, fdNumber); | ||
writeFileSync(STDERR_FD, finalLines); | ||
}; | ||
const STDERR_FD = 2; | ||
const getVerboseObject = ({ | ||
type, | ||
result, | ||
verboseInfo: {escapedCommand, commandId, rawOptions: {piped = false, ...options}}, | ||
}) => ({ | ||
type, | ||
escapedCommand, | ||
commandId: `${commandId}`, | ||
timestamp: new Date(), | ||
piped, | ||
result, | ||
options, | ||
}); | ||
const addPrefix = (string, verboseId, icon, color) => string.includes('\n') | ||
? string | ||
.split('\n') | ||
.map(line => addPrefixToLine(line, verboseId, icon, color)) | ||
.join('\n') | ||
: addPrefixToLine(string, verboseId, icon, color); | ||
const getPrintedLines = (verboseMessage, verboseObject) => verboseMessage | ||
.split('\n') | ||
.map(message => getPrintedLine({...verboseObject, message})); | ||
const addPrefixToLine = (line, verboseId, icon, color = identity) => [ | ||
gray(`[${getTimestamp()}]`), | ||
gray(`[${verboseId}]`), | ||
color(ICONS[icon]), | ||
color(line), | ||
].join(' '); | ||
const identity = string => string; | ||
// Prepending the timestamp allows debugging the slow paths of a subprocess | ||
const getTimestamp = () => { | ||
const date = new Date(); | ||
return `${padField(date.getHours(), 2)}:${padField(date.getMinutes(), 2)}:${padField(date.getSeconds(), 2)}.${padField(date.getMilliseconds(), 3)}`; | ||
const getPrintedLine = verboseObject => { | ||
const verboseLine = defaultVerboseFunction(verboseObject); | ||
return {verboseLine, verboseObject}; | ||
}; | ||
const padField = (field, padding) => String(field).padStart(padding, '0'); | ||
// Unless a `verbose` function is used, print all logs on `stderr` | ||
const STDERR_FD = 2; | ||
const ICONS = { | ||
command: '$', | ||
pipedCommand: '|', | ||
output: ' ', | ||
ipc: '*', | ||
error: figures.cross, | ||
warning: figures.warning, | ||
success: figures.tick, | ||
}; | ||
// Serialize any type to a line string, for logging | ||
export const serializeLogMessage = message => { | ||
export const serializeVerboseMessage = message => { | ||
const messageString = typeof message === 'string' ? message : inspect(message); | ||
@@ -52,0 +44,0 @@ const escapedMessage = escapeLines(messageString); |
import {BINARY_ENCODINGS} from '../arguments/encoding-option.js'; | ||
import {TRANSFORM_TYPES} from '../stdio/type.js'; | ||
import {verboseLog, serializeLogMessage} from './log.js'; | ||
import {verboseLog, serializeVerboseMessage} from './log.js'; | ||
import {isFullVerbose} from './values.js'; | ||
@@ -10,4 +11,4 @@ // `ignore` opts-out of `verbose` for a specific stream. | ||
// This only leaves with `pipe` and `overlapped`. | ||
export const shouldLogOutput = ({stdioItems, encoding, verboseInfo: {verbose}, fdNumber}) => fdNumber !== 'all' | ||
&& verbose[fdNumber] === 'full' | ||
export const shouldLogOutput = ({stdioItems, encoding, verboseInfo, fdNumber}) => fdNumber !== 'all' | ||
&& isFullVerbose(verboseInfo, fdNumber) | ||
&& !BINARY_ENCODINGS.has(encoding) | ||
@@ -27,6 +28,6 @@ && fdUsesVerbose(fdNumber) | ||
// `verbose: 'full'` printing logic with async methods | ||
export const logLines = async (linesIterable, stream, verboseInfo) => { | ||
export const logLines = async (linesIterable, stream, fdNumber, verboseInfo) => { | ||
for await (const line of linesIterable) { | ||
if (!isPipingStream(stream)) { | ||
logLine(line, verboseInfo); | ||
logLine(line, fdNumber, verboseInfo); | ||
} | ||
@@ -37,5 +38,5 @@ } | ||
// `verbose: 'full'` printing logic with sync methods | ||
export const logLinesSync = (linesArray, verboseInfo) => { | ||
export const logLinesSync = (linesArray, fdNumber, verboseInfo) => { | ||
for (const line of linesArray) { | ||
logLine(line, verboseInfo); | ||
logLine(line, fdNumber, verboseInfo); | ||
} | ||
@@ -54,4 +55,10 @@ }; | ||
// When `verbose` is `full`, print stdout|stderr | ||
const logLine = (line, {verboseId}) => { | ||
verboseLog(serializeLogMessage(line), verboseId, 'output'); | ||
const logLine = (line, fdNumber, verboseInfo) => { | ||
const verboseMessage = serializeVerboseMessage(line); | ||
verboseLog({ | ||
type: 'output', | ||
verboseMessage, | ||
fdNumber, | ||
verboseInfo, | ||
}); | ||
}; |
@@ -1,13 +0,15 @@ | ||
import {bold} from 'yoctocolors'; | ||
import {isVerbose} from './info.js'; | ||
import {isVerbose} from './values.js'; | ||
import {verboseLog} from './log.js'; | ||
// When `verbose` is `short|full`, print each command | ||
export const logCommand = (escapedCommand, {verbose, verboseId}, {piped = false}) => { | ||
if (!isVerbose(verbose)) { | ||
// When `verbose` is `short|full|custom`, print each command | ||
export const logCommand = (escapedCommand, verboseInfo) => { | ||
if (!isVerbose(verboseInfo)) { | ||
return; | ||
} | ||
const icon = piped ? 'pipedCommand' : 'command'; | ||
verboseLog(escapedCommand, verboseId, icon, bold); | ||
verboseLog({ | ||
type: 'command', | ||
verboseMessage: escapedCommand, | ||
verboseInfo, | ||
}); | ||
}; |
{ | ||
"name": "execa", | ||
"version": "9.2.0", | ||
"version": "9.3.0", | ||
"description": "Process execution for humans", | ||
@@ -25,3 +25,3 @@ "license": "MIT", | ||
"lint": "xo", | ||
"unit": "c8 ava", | ||
"unit": "c8 --merge-async ava", | ||
"type": "tsd && tsc && npx --yes tsd@0.29.0 && npx --yes --package typescript@5.1 tsc" | ||
@@ -71,3 +71,3 @@ }, | ||
"ava": "^6.0.1", | ||
"c8": "^9.1.0", | ||
"c8": "^10.1.2", | ||
"get-node": "^15.0.0", | ||
@@ -74,0 +74,0 @@ "is-in-ci": "^0.1.0", |
@@ -7,2 +7,3 @@ import type {SignalConstants} from 'node:os'; | ||
import type {StdinOptionCommon, StdoutStderrOptionCommon, StdioOptionsProperty} from '../stdio/type.js'; | ||
import type {VerboseOption} from '../verbose.js'; | ||
import type {FdGenericOption} from './specific.js'; | ||
@@ -230,4 +231,6 @@ import type {EncodingOption} from './encoding-option.js'; | ||
If `verbose` is `'full'`, the command's [`stdout`](https://en.wikipedia.org/wiki/Standard_streams#Standard_output_(stdout)), `stderr` and IPC messages are also printed. | ||
If `verbose` is `'full'` or a function, the command's [`stdout`](https://en.wikipedia.org/wiki/Standard_streams#Standard_output_(stdout)), `stderr` and IPC messages are also printed. | ||
A function can be passed to customize logging. | ||
By default, this applies to both `stdout` and `stderr`, but different values can also be passed. | ||
@@ -237,3 +240,3 @@ | ||
*/ | ||
readonly verbose?: FdGenericOption<'none' | 'short' | 'full'>; | ||
readonly verbose?: VerboseOption; | ||
@@ -240,0 +243,0 @@ /** |
@@ -182,5 +182,5 @@ import type {SignalConstants} from 'node:os'; | ||
type SuccessResult< | ||
IsSync extends boolean, | ||
OptionsType extends CommonOptions, | ||
export type SuccessResult< | ||
IsSync extends boolean = boolean, | ||
OptionsType extends CommonOptions = CommonOptions, | ||
> = InstanceType<typeof CommonResult<IsSync, OptionsType>> & OmitErrorIfReject<OptionsType['reject']>; | ||
@@ -187,0 +187,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
320815
141
7784