@nx.js/repl
Version:
Read-Eval-Print Loop for nx.js
127 lines • 4.33 kB
JavaScript
import { erase } from 'sisteransi';
import { bold, cyan, bgYellow } from 'kleur/colors';
const decoder = new TextDecoder();
const encoder = new TextEncoder();
const cursorChar = (v) => bold(bgYellow(v || ' '));
const AsyncFunction = async function () { }.constructor;
export class REPL {
buffer = '';
historyIndex = 0;
cursorPosition = 0;
history;
prompt;
writer;
inspect;
constructor(writer, opts) {
this.writer = writer;
this.history = [];
this.prompt = opts?.prompt ?? bold(cyan('> '));
this.inspect = opts?.inspect ?? Switch.inspect;
}
async renderPrompt(extra = '') {
let b = this.buffer;
if (this.cursorPosition >= 0) {
const bufferL = this.buffer.slice(0, this.cursorPosition);
const bufferP = this.buffer[this.cursorPosition];
const bufferR = this.buffer.slice(this.cursorPosition + 1);
b = `${bufferL}${cursorChar(bufferP)}${bufferR}`;
}
await this.print(`\r${erase.line}${this.prompt}${b}${extra}`);
}
async print(str) {
await this.writer.write(encoder.encode(str.replace(/(?:\r\n|\n)/g, '\r\n')));
}
async write(data) {
this.buffer = `${this.buffer.slice(0, this.cursorPosition)}${decoder.decode(data)}${this.buffer.slice(this.cursorPosition)}`;
this.cursorPosition += data.length;
await this.renderPrompt();
}
async submit() {
// Remove cursor
this.cursorPosition = -1;
await this.renderPrompt('\n');
try {
this.history.push(this.buffer);
this.historyIndex = this.history.length;
const trimmed = this.buffer.trim();
let result = undefined;
if (trimmed.length > 0) {
if (/\bawait\b/.test(trimmed)) {
const r = await AsyncFunction(`try {
var v = (${trimmed});
if (v && typeof v.catch === 'function') v.catch();
return { v }
} catch (err) {
return { err }
}`)();
if (r.err)
throw r.err;
result = r.v;
}
else {
try {
result = (0, eval)(`(${trimmed})`);
}
catch (err) {
if (err instanceof SyntaxError) {
result = (0, eval)(trimmed);
}
else {
throw err;
}
}
}
}
if (typeof result?.catch === 'function')
result.catch();
this.buffer = '';
this.cursorPosition = 0;
Object.defineProperty(globalThis, '_', {
value: result,
enumerable: false,
configurable: true,
});
await this.print(`${this.inspect(result)}\n\n`);
}
catch (err) {
this.buffer = '';
this.cursorPosition = 0;
await this.print(`Uncaught ${this.inspect(err)}\n`);
}
await this.renderPrompt();
}
async backspace() {
if (this.buffer.length) {
this.buffer = `${this.buffer.slice(0, this.cursorPosition - 1)}${this.buffer.slice(this.cursorPosition)}`;
this.cursorPosition--;
await this.renderPrompt();
}
}
async arrowUp() {
if (this.historyIndex > 0) {
this.buffer = this.history[--this.historyIndex];
this.cursorPosition = this.buffer.length;
await this.renderPrompt();
}
}
async arrowDown() {
if (this.historyIndex < this.history.length) {
this.buffer = this.history[++this.historyIndex] ?? '';
this.cursorPosition = this.buffer.length;
await this.renderPrompt();
}
}
async arrowLeft() {
if (this.cursorPosition > 0) {
this.cursorPosition--;
await this.renderPrompt();
}
}
async arrowRight() {
if (this.cursorPosition < this.buffer.length) {
this.cursorPosition++;
await this.renderPrompt();
}
}
}
//# sourceMappingURL=index.js.map