【问题标题】:How can I start a REPL that can access local variables in node.js?如何启动可以访问 node.js 中的局部变量的 REPL?
【发布时间】:2020-09-02 06:02:14
【问题描述】:

就像from IPython import embed; embed(),但对于node

我想以编程方式打开一个 REPL shell 并至少能够读取局部变量。能够更改它们也是一个优点。

【问题讨论】:

  • 局部变量是指环境变量?
  • @MarcosCasagrande 不,我的意思是本地 javascript 变量。
  • 嗨,如果你需要 JS repl,我想你只需要编写节点命令 follow this
  • 我为deno 提交了一个工作示例,如果您想要Node.js 的示例,请告诉我。

标签: javascript node.js read-eval-print-loop deno


【解决方案1】:

对于deno(标题为Node.js,标记 deno),您可以使用Deno.run 执行deno 并写入stdin 并从stdout 读取。

以下会做:

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)

如果你运行 sn-p,输出将是:

Command: let x = 5;
Command: x
Value: 5

Command:  x = 6;
Command:  x
Value:  6

需要进行一些改进,例如处理stderr,但你明白了。

【讨论】:

  • 谢谢!我喜欢这个除了我的问题之外的其他目的,但我认为它不能回答我的问题;我想使用 REPL 作为调试辅助。我需要它在正常的 javascript 执行过程中打开,而不是作为一个独立的进程。我需要 REPL 能够访问运行它的作用域的局部变量。
  • 那么你需要一个调试器。
  • 我想要一个可嵌入的 REPL,它也可以用作调试器。有这样的工具吗?
  • 没有这个工具可用,你可以查看Deno debugger
【解决方案2】:

此功能目前不存在,但正在https://github.com/denoland/deno/issues/7938 中提出。

愿景类似于

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

【讨论】:

    【解决方案3】:

    您可以构建一个类似于内置 Deno REPL 的 REPL,并使用 dangerous eval 函数评估表达式。通过它,您将能够访问局部变量和其他内容(例如window)。

    repl.ts

    import { readLines, writeAll } from "https://deno.land/std@0.106.0/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));
    

    示例用法

    % deno run repl_demo.ts
    exit using ctrl+d or close()
    > a
    1
    > a = 40
    40
    > a + b
    42
    

    【讨论】:

      【解决方案4】:

      据我所知,最接近的方法是使用 repl 内置模块(由 node inspect 本身使用):

      // ... 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;
      

      通过运行node index.js(假设您将上述内容保存在index.js)我们可以访问这个自定义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 > 
      

      但是,它不像调试器工具那样工作,但实际上,它只是一个 REPL。

      【讨论】:

      • 我们如何自动暴露作用域内的所有本地变量?另外,我认为这种方法不允许更改局部变量然后恢复执行。
      • @HappyFace 您将不得不公开它们,或者创建一个实用函数以更简单的方式公开它们。实际上,这不会暂停脚本的执行——因为你需要使用debuggers 或断点启动一个node inspect 进程......我只是想知道为什么需要这样一个类似python 的实用程序首先——也许我们可以找到更好的选择。命令行的Node.js调试器相当不错,IDE也有可视化的调试界面...
      【解决方案5】:
      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();
      

      此代码使用 readLine 模块询问输入,每次提供响应时,代码都会执行并且新的输入是 askef

      【讨论】:

      • edit您的回答提供有关您提供的代码如何工作、您已更改的内容等的更多信息。纯代码的答案可能会解决原始提问者的问题,但他们不要帮助未来的读者理解解决方案。
      猜你喜欢
      • 2012-06-27
      • 1970-01-01
      • 2019-07-31
      • 2011-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-29
      • 2017-10-17
      相关资源
      最近更新 更多