basant307/AI_Governance_Project
048
1import {createReadStream, readFileSync} from 'node:fs';2import {setTimeout} from 'node:timers/promises';3import {isStream} from 'is-stream';4import getStream, {getStreamAsBuffer} from 'get-stream';5import mergeStream from 'merge-stream';6 7const validateInputOptions = input => {8 if (input !== undefined) {9 throw new TypeError('The `input` and `inputFile` options cannot be both set.');10 }11};12 13const getInputSync = ({input, inputFile}) => {14 if (typeof inputFile !== 'string') {15 return input;16 }17 18 validateInputOptions(input);19 return readFileSync(inputFile);20};21 22// `input` and `inputFile` option in sync mode23export const handleInputSync = options => {24 const input = getInputSync(options);25 26 if (isStream(input)) {27 throw new TypeError('The `input` option cannot be a stream in sync mode');28 }29 30 return input;31};32 33const getInput = ({input, inputFile}) => {34 if (typeof inputFile !== 'string') {35 return input;36 }37 38 validateInputOptions(input);39 return createReadStream(inputFile);40};41 42// `input` and `inputFile` option in async mode43export const handleInput = (spawned, options) => {44 const input = getInput(options);45 46 if (input === undefined) {47 return;48 }49 50 if (isStream(input)) {51 input.pipe(spawned.stdin);52 } else {53 spawned.stdin.end(input);54 }55};56 57// `all` interleaves `stdout` and `stderr`58export const makeAllStream = (spawned, {all}) => {59 if (!all || (!spawned.stdout && !spawned.stderr)) {60 return;61 }62 63 const mixed = mergeStream();64 65 if (spawned.stdout) {66 mixed.add(spawned.stdout);67 }68 69 if (spawned.stderr) {70 mixed.add(spawned.stderr);71 }72 73 return mixed;74};75 76// On failure, `result.stdout|stderr|all` should contain the currently buffered stream77const getBufferedData = async (stream, streamPromise) => {78 // When `buffer` is `false`, `streamPromise` is `undefined` and there is no buffered data to retrieve79 if (!stream || streamPromise === undefined) {80 return;81 }82 83 // Wait for the `all` stream to receive the last chunk before destroying the stream84 await setTimeout(0);85 86 stream.destroy();87 88 try {89 return await streamPromise;90 } catch (error) {91 return error.bufferedData;92 }93};94 95const getStreamPromise = (stream, {encoding, buffer, maxBuffer}) => {96 if (!stream || !buffer) {97 return;98 }99 100 // eslint-disable-next-line unicorn/text-encoding-identifier-case101 if (encoding === 'utf8' || encoding === 'utf-8') {102 return getStream(stream, {maxBuffer});103 }104 105 if (encoding === null || encoding === 'buffer') {106 return getStreamAsBuffer(stream, {maxBuffer});107 }108 109 return applyEncoding(stream, maxBuffer, encoding);110};111 112const applyEncoding = async (stream, maxBuffer, encoding) => {113 const buffer = await getStreamAsBuffer(stream, {maxBuffer});114 return buffer.toString(encoding);115};116 117// Retrieve result of child process: exit code, signal, error, streams (stdout/stderr/all)118export const getSpawnedResult = async ({stdout, stderr, all}, {encoding, buffer, maxBuffer}, processDone) => {119 const stdoutPromise = getStreamPromise(stdout, {encoding, buffer, maxBuffer});120 const stderrPromise = getStreamPromise(stderr, {encoding, buffer, maxBuffer});121 const allPromise = getStreamPromise(all, {encoding, buffer, maxBuffer: maxBuffer * 2});122 123 try {124 return await Promise.all([processDone, stdoutPromise, stderrPromise, allPromise]);125 } catch (error) {126 return Promise.all([127 {error, signal: error.signal, timedOut: error.timedOut},128 getBufferedData(stdout, stdoutPromise),129 getBufferedData(stderr, stderrPromise),130 getBufferedData(all, allPromise),131 ]);132 }133};134 