Files
bare-operating-system/packages/bare-os-booter/lib/cli-readline.js
T
Raven Scott 2e26b14250
CI / test (push) Failing after 4m56s
updates
2026-04-02 22:35:09 -04:00

96 lines
2.4 KiB
JavaScript

/**
* Line-oriented stdin for Bare/Pear (no node:readline) and Node fallback.
* Pear-terminal uses bare-readline + bare-stdio; we mirror that after Node readline.
*/
/**
* @param {import('stream').Readable} stdin
* @param {import('stream').Writable} stdout
* @returns {(prompt: string) => Promise<string>}
*/
export async function createBareReadlineQuestion(stdin, stdout) {
const mod = await import('bare-readline')
const createInterface = mod.createInterface ?? mod.default?.createInterface
if (typeof createInterface !== 'function') {
throw new Error('bare-readline: createInterface missing')
}
const rl = createInterface({
input: stdin,
output: stdout,
prompt: ''
})
return (prompt) =>
new Promise((resolve) => {
rl.setPrompt(prompt)
rl.prompt()
rl.once('line', (line) => {
resolve(line)
})
})
}
/**
* @param {import('stream').Readable} stdin
* @param {import('stream').Writable} stdout
* @returns {(prompt: string) => Promise<string | null>}
*/
export function createStreamLineReader(stdin, stdout) {
let buf = ''
/** @type {string[]} */
const queue = []
/** @type {((line: string | null) => void)[]} */
const waiters = []
function deliver(line) {
if (waiters.length) waiters.shift()(line)
else queue.push(line)
}
function onData(chunk) {
const s =
typeof chunk === 'string' ? chunk : Buffer.from(chunk).toString('utf8')
buf += s
let i
while ((i = buf.indexOf('\n')) !== -1) {
const raw = buf.slice(0, i)
buf = buf.slice(i + 1)
deliver(raw.replace(/\r$/, ''))
}
}
function flushRemainder() {
if (buf.length) {
deliver(buf.replace(/\r$/, ''))
buf = ''
}
}
function onEnd() {
flushRemainder()
while (waiters.length) waiters.shift()(null)
}
if (typeof stdin.setEncoding === 'function') stdin.setEncoding('utf8')
stdin.on('data', onData)
stdin.on('end', onEnd)
stdin.on('error', onEnd)
if (typeof stdin.resume === 'function') stdin.resume()
return function readLine(prompt) {
if (typeof stdout.write === 'function') stdout.write(prompt)
if (queue.length) return Promise.resolve(queue.shift() ?? null)
return new Promise((resolve) => waiters.push(resolve))
}
}
/**
* @returns {boolean}
*/
export function looksLikeInteractiveStdin(stdin) {
return Boolean(
stdin &&
typeof stdin.on === 'function' &&
typeof stdin.resume === 'function'
)
}