Just like from IPython import embed; embed()
but for node
.
I want to open a REPL shell programmatically and be able to at least read the local variables. Being able to change them as well is a plus.
If you have node installed, then you also have the Node. js REPL. To start it, simply enter node in your command line shell: node.
REPL stands for "Read Eval Print Loop". 3) Which of the following command is used to start a REPL session? Answer: A is the correct option. We can start REPL simply by running node on shell/console without any argument.
As far I know, the closest you can get is by using the repl
built-in module (which is used by node inspect
itself):
// ... your code you want to debug
const repl = require("repl");
const replServer = repl.start({
prompt: "Your Own Repl > ",
useGlobal: true
});
// Expose variables
const localVar = 42
replServer.context.localVar = localVar;
By running node index.js
(assuming you saved the above content in index.js
) we get access to this custom repl:
$ node index.js
Your Own Repl > localVar
42
Your Own Repl >
(To exit, press Ctrl+C again or Ctrl+D or type .exit)
Your Own Repl >
However, this does not work like a debugger tool, but really, it's only a REPL.
You can build a REPL similar to the built-in Deno REPL and and evaluate expressions using the dangerous eval
function. Through it you'll be able to access local variables and other things (e.g. window
).
repl.ts
import { readLines, writeAll } from "https://deno.land/[email protected]/io/mod.ts";
export default async function repl(evaluate: (x: string) => unknown) {
await writeOutput("exit using ctrl+d or close()\n");
await writeOutput("> ");
for await (const input of readInputs()) {
try {
const value = evaluate(input);
const output = `${Deno.inspect(value, { colors: !Deno.noColor })}\n`;
await writeOutput(output);
await writeOutput("> ");
} catch (error) {
await writeError(error);
}
}
}
async function* readInputs(): AsyncIterableIterator<string> {
yield* readLines(Deno.stdin);
}
async function writeOutput(output: string) {
await writeAll(Deno.stdout, new TextEncoder().encode(output));
}
async function writeError(error: unknown) {
await writeAll(Deno.stderr, new TextEncoder().encode(`Uncaught ${error}\n`));
}
repl_demo.ts
import repl from "./repl.ts";
let a = 1;
let b = 2;
let c = 3;
await repl((x) => eval(x));
example usage
% deno run repl_demo.ts
exit using ctrl+d or close()
> a
1
> a = 40
40
> a + b
42
For deno
(Title says Node.js, tag deno) you can use Deno.run
to execute deno
and write to stdin
and read from stdout
.
The following will do:
const p = Deno.run({
cmd: ["deno"],
stdin: "piped",
stdout: "piped",
stderr: "piped"
});
async function read(waitForMessage) {
const reader = Deno.iter(p.stdout)
let res = '';
for await(const chunk of reader) {
res += new TextDecoder().decode(chunk);
console.log('Chunk', res, '---')
// improve this, you should wait until the last chunk
// is read in case of a command resulting in a big output
if(!waitForMessage)
return res;
else if(res.includes(waitForMessage))
return res;
}
}
async function writeCommand(command) {
const msg = new TextEncoder().encode(command + '\n');
console.log('Command: ', command)
const readPromise = read();
// write command
await p.stdin.write(msg);
// Wait for output
const value = await readPromise
return value;
}
// Wait for initial output:
// Deno 1.0.0
// exit using ctrl+d or close()
await read('ctrl+d or close()');
await writeCommand('let x = 5;')
let value = await writeCommand('x') // read x
console.log('Value: ', value)
await writeCommand('x = 6;')
value = await writeCommand('x') // read x
console.log('Value: ', value)
If you run that snippet, the output will be:
Command: let x = 5;
Command: x
Value: 5
Command: x = 6;
Command: x
Value: 6
There are some improvements to be made, such as handling stderr
but you get the idea.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With