136 lines
3.8 KiB
JavaScript
136 lines
3.8 KiB
JavaScript
import {writeFileSync, appendFileSync} from 'node:fs';
|
|
import {shouldLogOutput, logLinesSync} from '../verbose/output.js';
|
|
import {runGeneratorsSync} from '../transform/generator.js';
|
|
import {splitLinesSync} from '../transform/split.js';
|
|
import {joinToString, joinToUint8Array, bufferToUint8Array} from '../utils/uint-array.js';
|
|
import {FILE_TYPES} from '../stdio/type.js';
|
|
import {truncateMaxBufferSync} from './max-buffer.js';
|
|
|
|
// Apply `stdout`/`stderr` options, after spawning, in sync mode
|
|
export const transformOutputSync = ({fileDescriptors, syncResult: {output}, options, isMaxBuffer, verboseInfo}) => {
|
|
if (output === null) {
|
|
return {output: Array.from({length: 3})};
|
|
}
|
|
|
|
const state = {};
|
|
const outputFiles = new Set([]);
|
|
const transformedOutput = output.map((result, fdNumber) =>
|
|
transformOutputResultSync({
|
|
result,
|
|
fileDescriptors,
|
|
fdNumber,
|
|
state,
|
|
outputFiles,
|
|
isMaxBuffer,
|
|
verboseInfo,
|
|
}, options));
|
|
return {output: transformedOutput, ...state};
|
|
};
|
|
|
|
const transformOutputResultSync = (
|
|
{result, fileDescriptors, fdNumber, state, outputFiles, isMaxBuffer, verboseInfo},
|
|
{buffer, encoding, lines, stripFinalNewline, maxBuffer},
|
|
) => {
|
|
if (result === null) {
|
|
return;
|
|
}
|
|
|
|
const truncatedResult = truncateMaxBufferSync(result, isMaxBuffer, maxBuffer);
|
|
const uint8ArrayResult = bufferToUint8Array(truncatedResult);
|
|
const {stdioItems, objectMode} = fileDescriptors[fdNumber];
|
|
const chunks = runOutputGeneratorsSync([uint8ArrayResult], stdioItems, encoding, state);
|
|
const {serializedResult, finalResult = serializedResult} = serializeChunks({
|
|
chunks,
|
|
objectMode,
|
|
encoding,
|
|
lines,
|
|
stripFinalNewline,
|
|
fdNumber,
|
|
});
|
|
|
|
logOutputSync({
|
|
serializedResult,
|
|
fdNumber,
|
|
state,
|
|
verboseInfo,
|
|
encoding,
|
|
stdioItems,
|
|
objectMode,
|
|
});
|
|
|
|
const returnedResult = buffer[fdNumber] ? finalResult : undefined;
|
|
|
|
try {
|
|
if (state.error === undefined) {
|
|
writeToFiles(serializedResult, stdioItems, outputFiles);
|
|
}
|
|
|
|
return returnedResult;
|
|
} catch (error) {
|
|
state.error = error;
|
|
return returnedResult;
|
|
}
|
|
};
|
|
|
|
// Applies transform generators to `stdout`/`stderr`
|
|
const runOutputGeneratorsSync = (chunks, stdioItems, encoding, state) => {
|
|
try {
|
|
return runGeneratorsSync(chunks, stdioItems, encoding, false);
|
|
} catch (error) {
|
|
state.error = error;
|
|
return chunks;
|
|
}
|
|
};
|
|
|
|
// The contents is converted to three stages:
|
|
// - serializedResult: used when the target is a file path/URL or a file descriptor (including 'inherit')
|
|
// - finalResult/returnedResult: returned as `result.std*`
|
|
const serializeChunks = ({chunks, objectMode, encoding, lines, stripFinalNewline, fdNumber}) => {
|
|
if (objectMode) {
|
|
return {serializedResult: chunks};
|
|
}
|
|
|
|
if (encoding === 'buffer') {
|
|
return {serializedResult: joinToUint8Array(chunks)};
|
|
}
|
|
|
|
const serializedResult = joinToString(chunks, encoding);
|
|
if (lines[fdNumber]) {
|
|
return {serializedResult, finalResult: splitLinesSync(serializedResult, !stripFinalNewline[fdNumber], objectMode)};
|
|
}
|
|
|
|
return {serializedResult};
|
|
};
|
|
|
|
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
|
|
const writeToFiles = (serializedResult, stdioItems, outputFiles) => {
|
|
for (const {path, append} of stdioItems.filter(({type}) => FILE_TYPES.has(type))) {
|
|
const pathString = typeof path === 'string' ? path : path.toString();
|
|
if (append || outputFiles.has(pathString)) {
|
|
appendFileSync(path, serializedResult);
|
|
} else {
|
|
outputFiles.add(pathString);
|
|
writeFileSync(path, serializedResult);
|
|
}
|
|
}
|
|
};
|