9

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.

4
  • by local variables you mean environment variables? Commented May 16, 2020 at 11:15
  • @MarcosCasagrande No, I mean local javascript variables. Commented May 16, 2020 at 11:15
  • Hi, I think you if you need JS repl- you need to just write node command only follow this Commented May 16, 2020 at 11:51
  • I submitted a working example for deno, if you want it for Node.js let me know. Commented May 16, 2020 at 12:04

5 Answers 5

5
+50

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.

Sign up to request clarification or add additional context in comments.

2 Comments

How do we automatically expose all local vars in the scope? Also, I think this method doesn't allow changing the local variables and then resuming the execution.
@HappyFace You will have to expose them, or create a utility function to expose them in an easier way. Indeed, this will not pause the execution of the script – for that you'd need to start a node inspect process with debuggers or breakpoints... I am just wondering why such a python-like utility would be needed in the first place – maybe we could find better alternatives. The command line Node.js debugger is quite good, and the IDEs have visual debugging interfaces too...
2

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

Comments

2

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.

4 Comments

Thanks! I like this for other purposes than my question, but I don't think it answers my question; I want to use the REPL as a debugging aid. I need it to open in the middle of the normal javascript execution, not as a standalone process. I need the REPL to be able to access the local variables of the scope that runs it.
You want a debugger then.
I want an embeddable REPL that can also be used as a debugger. Is there such a tool available?
There isn't such tool available, you can check Deno debugger
2

This feature doesn't currently exist but is being proposed in https://github.com/denoland/deno/issues/7938.

The vision being something along the lines of

Deno.eval("Deno.repl()")

Comments

1
const readline = require('readline');

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});
//to be sure this context is here
const ev = eval.bind(this);
function ask() {
     rl.question('>', (code) => {
           console.log(ev(code));
           ask();
     });
} 
ask();

this code ask a input with readLine module and every time a reponse is provided the code is executed and a new input is askef

1 Comment

Please edit your answer to provide more information as to how the code you've provided works, what you have changed, etc. Code-only answers might solve the problem of the original asker but they don't help future readers understand the solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.