The Standard Library has been moved to JSR. See the blog post for details.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.// Copyright Joyent, Inc. and other Node contributors.//// Permission is hereby granted, free of charge, to any person obtaining a// copy of this software and associated documentation files (the// "Software"), to deal in the Software without restriction, including// without limitation the rights to use, copy, modify, merge, publish,// distribute, sublicense, and/or sell copies of the Software, and to permit// persons to whom the Software is furnished to do so, subject to the// following conditions://// The above copyright notice and this permission notice shall be included// in all copies or substantial portions of the Software.//// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE// USE OR OTHER DEALINGS IN THE SOFTWARE.
// deno-lint-ignore-file camelcase
import { clearLine, clearScreenDown, cursorTo, moveCursor,} from "./internal/readline/callbacks.mjs";import { emitKeypressEvents } from "./internal/readline/emitKeypressEvents.mjs";import promises from "./readline/promises.ts";import { validateAbortSignal } from "./internal/validators.mjs";import { promisify } from "./internal/util.mjs";import { AbortError } from "./internal/errors.ts";import { process } from "./process.ts";
import { Interface as _Interface, InterfaceConstructor, kAddHistory, kDecoder, kDeleteLeft, kDeleteLineLeft, kDeleteLineRight, kDeleteRight, kDeleteWordLeft, kDeleteWordRight, kGetDisplayPos, kHistoryNext, kHistoryPrev, kInsertString, kLine, kLine_buffer, kMoveCursor, kNormalWrite, kOldPrompt, kOnLine, kPreviousKey, kPrompt, kQuestion, kQuestionCallback, kQuestionCancel, kRefreshLine, kSawKeyPress, kSawReturnAt, kSetRawMode, kTabComplete, kTabCompleter, kTtyWrite, kWordLeft, kWordRight, kWriteToOutput,} from "./internal/readline/interface.mjs";
function Interface(input, output, completer, terminal) { if (!(this instanceof Interface)) { return new Interface(input, output, completer, terminal); }
if ( input?.input && typeof input.completer === "function" && input.completer.length !== 2 ) { const { completer } = input; input.completer = (v, cb) => cb(null, completer(v)); } else if (typeof completer === "function" && completer.length !== 2) { const realCompleter = completer; completer = (v, cb) => cb(null, realCompleter(v)); }
// NOTE(bartlomieju): in Node this is `FunctionPrototypeCall(...)`, // but trying to do `Function.prototype.call()` somehow doesn't work here // /shrug InterfaceConstructor.bind( this, )( input, output, completer, terminal, ); if (process.env.TERM === "dumb") { this._ttyWrite = _ttyWriteDumb.bind(this); }}
Object.setPrototypeOf(Interface.prototype, _Interface.prototype);Object.setPrototypeOf(Interface, _Interface);
/** * Displays `query` by writing it to the `output`. * @param {string} query * @param {{ signal?: AbortSignal; }} [options] * @param {Function} cb * @returns {void} */Interface.prototype.question = function question(query, options, cb) { cb = typeof options === "function" ? options : cb; options = typeof options === "object" && options !== null ? options : {};
if (options.signal) { validateAbortSignal(options.signal, "options.signal"); if (options.signal.aborted) { return; }
const onAbort = () => { this[kQuestionCancel](); }; options.signal.addEventListener("abort", onAbort, { once: true }); const cleanup = () => { options.signal.removeEventListener(onAbort); }; cb = typeof cb === "function" ? (answer) => { cleanup(); return cb(answer); } : cleanup; }
if (typeof cb === "function") { this[kQuestion](query, cb); }};Interface.prototype.question[promisify.custom] = function question( query, options,) { options = typeof options === "object" && options !== null ? options : {};
if (options.signal && options.signal.aborted) { return Promise.reject( new AbortError(undefined, { cause: options.signal.reason }), ); }
return new Promise((resolve, reject) => { let cb = resolve;
if (options.signal) { const onAbort = () => { reject(new AbortError(undefined, { cause: options.signal.reason })); }; options.signal.addEventListener("abort", onAbort, { once: true }); cb = (answer) => { options.signal.removeEventListener("abort", onAbort); resolve(answer); }; }
this.question(query, options, cb); });};
/** * Creates a new `readline.Interface` instance. * @param {Readable | { * input: Readable; * output: Writable; * completer?: Function; * terminal?: boolean; * history?: string[]; * historySize?: number; * removeHistoryDuplicates?: boolean; * prompt?: string; * crlfDelay?: number; * escapeCodeTimeout?: number; * tabSize?: number; * signal?: AbortSignal; * }} input * @param {Writable} [output] * @param {Function} [completer] * @param {boolean} [terminal] * @returns {Interface} */function createInterface(input, output, completer, terminal) { return new Interface(input, output, completer, terminal);}
Object.defineProperties(Interface.prototype, { // Redirect internal prototype methods to the underscore notation for backward // compatibility. [kSetRawMode]: { get() { return this._setRawMode; }, }, [kOnLine]: { get() { return this._onLine; }, }, [kWriteToOutput]: { get() { return this._writeToOutput; }, }, [kAddHistory]: { get() { return this._addHistory; }, }, [kRefreshLine]: { get() { return this._refreshLine; }, }, [kNormalWrite]: { get() { return this._normalWrite; }, }, [kInsertString]: { get() { return this._insertString; }, }, [kTabComplete]: { get() { return this._tabComplete; }, }, [kWordLeft]: { get() { return this._wordLeft; }, }, [kWordRight]: { get() { return this._wordRight; }, }, [kDeleteLeft]: { get() { return this._deleteLeft; }, }, [kDeleteRight]: { get() { return this._deleteRight; }, }, [kDeleteWordLeft]: { get() { return this._deleteWordLeft; }, }, [kDeleteWordRight]: { get() { return this._deleteWordRight; }, }, [kDeleteLineLeft]: { get() { return this._deleteLineLeft; }, }, [kDeleteLineRight]: { get() { return this._deleteLineRight; }, }, [kLine]: { get() { return this._line; }, }, [kHistoryNext]: { get() { return this._historyNext; }, }, [kHistoryPrev]: { get() { return this._historyPrev; }, }, [kGetDisplayPos]: { get() { return this._getDisplayPos; }, }, [kMoveCursor]: { get() { return this._moveCursor; }, }, [kTtyWrite]: { get() { return this._ttyWrite; }, },
// Defining proxies for the internal instance properties for backward // compatibility. _decoder: { get() { return this[kDecoder]; }, set(value) { this[kDecoder] = value; }, }, _line_buffer: { get() { return this[kLine_buffer]; }, set(value) { this[kLine_buffer] = value; }, }, _oldPrompt: { get() { return this[kOldPrompt]; }, set(value) { this[kOldPrompt] = value; }, }, _previousKey: { get() { return this[kPreviousKey]; }, set(value) { this[kPreviousKey] = value; }, }, _prompt: { get() { return this[kPrompt]; }, set(value) { this[kPrompt] = value; }, }, _questionCallback: { get() { return this[kQuestionCallback]; }, set(value) { this[kQuestionCallback] = value; }, }, _sawKeyPress: { get() { return this[kSawKeyPress]; }, set(value) { this[kSawKeyPress] = value; }, }, _sawReturnAt: { get() { return this[kSawReturnAt]; }, set(value) { this[kSawReturnAt] = value; }, },});
// Make internal methods public for backward compatibility.Interface.prototype._setRawMode = _Interface.prototype[kSetRawMode];Interface.prototype._onLine = _Interface.prototype[kOnLine];Interface.prototype._writeToOutput = _Interface.prototype[kWriteToOutput];Interface.prototype._addHistory = _Interface.prototype[kAddHistory];Interface.prototype._refreshLine = _Interface.prototype[kRefreshLine];Interface.prototype._normalWrite = _Interface.prototype[kNormalWrite];Interface.prototype._insertString = _Interface.prototype[kInsertString];Interface.prototype._tabComplete = function (lastKeypressWasTab) { // Overriding parent method because `this.completer` in the legacy // implementation takes a callback instead of being an async function. this.pause(); const string = this.line.slice(0, this.cursor); this.completer(string, (err, value) => { this.resume();
if (err) { // TODO(bartlomieju): inspect is not ported yet // this._writeToOutput(`Tab completion error: ${inspect(err)}`); this._writeToOutput(`Tab completion error: ${err}`); return; }
this[kTabCompleter](lastKeypressWasTab, value); });};Interface.prototype._wordLeft = _Interface.prototype[kWordLeft];Interface.prototype._wordRight = _Interface.prototype[kWordRight];Interface.prototype._deleteLeft = _Interface.prototype[kDeleteLeft];Interface.prototype._deleteRight = _Interface.prototype[kDeleteRight];Interface.prototype._deleteWordLeft = _Interface.prototype[kDeleteWordLeft];Interface.prototype._deleteWordRight = _Interface.prototype[kDeleteWordRight];Interface.prototype._deleteLineLeft = _Interface.prototype[kDeleteLineLeft];Interface.prototype._deleteLineRight = _Interface.prototype[kDeleteLineRight];Interface.prototype._line = _Interface.prototype[kLine];Interface.prototype._historyNext = _Interface.prototype[kHistoryNext];Interface.prototype._historyPrev = _Interface.prototype[kHistoryPrev];Interface.prototype._getDisplayPos = _Interface.prototype[kGetDisplayPos];Interface.prototype._getCursorPos = _Interface.prototype.getCursorPos;Interface.prototype._moveCursor = _Interface.prototype[kMoveCursor];Interface.prototype._ttyWrite = _Interface.prototype[kTtyWrite];
function _ttyWriteDumb(s, key) { key = key || {};
if (key.name === "escape") return;
if (this[kSawReturnAt] && key.name !== "enter") { this[kSawReturnAt] = 0; }
if (key.ctrl) { if (key.name === "c") { if (this.listenerCount("SIGINT") > 0) { this.emit("SIGINT"); } else { // This readline instance is finished this.close(); }
return; } else if (key.name === "d") { this.close(); return; } }
switch (key.name) { case "return": // Carriage return, i.e. \r this[kSawReturnAt] = Date.now(); this._line(); break;
case "enter": // When key interval > crlfDelay if ( this[kSawReturnAt] === 0 || Date.now() - this[kSawReturnAt] > this.crlfDelay ) { this._line(); } this[kSawReturnAt] = 0; break;
default: if (typeof s === "string" && s) { this.line += s; this.cursor += s.length; this._writeToOutput(s); } }}
export { clearLine, clearScreenDown, createInterface, cursorTo, emitKeypressEvents, Interface, moveCursor, promises,};