0

I wish to create one NodeJS source file in a Jupyter notebook which is using the IJavascript kernel so that I can quickly debug my code. Once I have it working, I can then use the "Download As..." feature of Jupyter to save the notebook as a NodeJS script file.

I'd like to have the ability to selectively ignore / include code in the notebook source that will not execute when I run the generated NodeJS script file.

I have solved this problem for doing a similar thing for Python Jupyter notebooks because I can determine if the code is running in an interactive session (IPython [REPL]). I accomplished this by using this function in Python:

def is_interactive():
    import __main__ as main
    return not hasattr(main, '__file__')

(Thanks to Tell if Python is in interactive mode)

Is there a way to do a similar thing for NodeJS?

3 Answers3

1

I don't know if this is the correct way but couldn't find anything else basically if you

try {
   const repl = __dirname
} catch (err) {
  //code run if repl
}

it feels a little hacky but works ¯\_(ツ)_/¯

rbfmh
  • 11
  • 2
  • This isn't really a good idea because it depends on the REPL using CommonJS, which may be changed in future versions of NodeJS. Not to mention CommonJS is the default execution environment for scripts that aren't explicitly marked as EJS Modules. So this could throw a false positive very frequently. – Ruby A. Rose Dec 05 '20 at 06:03
  • I think that won't work if you place it in a js file. – jtompl May 04 '21 at 23:48
1

The fastest and most reliable route would just be to query the process arguments. From the NodeJS executable alone, there are two ways to launch the REPL. Either you do something like this without any script following the call to node.

node --experimental-modules ...

Or you force node into the REPL using interactive mode.

node -i ...

The option ending parameter added in v6.11.0 -- will never append arguments into the process.argv array unless it's executing in script mode; via FILE, -p, or -e. Any arguments meant for NodeJS will be filtered into the accompanying process.execArgv variable, so the only thing left in the process.argv array should be process.execPath. Under these circumstances, we can reduce the query to the solution below.

const isREPL = process.execArgv.includes("-i") || process.argv.length === 1;

console.log(isREPL ? "You're in the REPL" : "You're running a script m8");

This isn't the most robust method since any user can otherwise instantiate a REPL from an intiator script which your code could be ran by. For that I'm pretty sure you could use an artificial error to crawl the traceback and look for a REPL entry. Although I haven't the time to implement and ensure that solution at this time.

Ruby A. Rose
  • 173
  • 1
  • 5
  • That doesn't work if I e.g. use `babel-node` . `isREPL` returns false for me then. – jtompl May 04 '21 at 23:49
  • I changed it to `const isREPL = !!require("repl").repl;` Not sure if that's always reliable though. – jtompl May 05 '21 at 00:14
  • @jtompl, I'll have to take a look at that and see if I can find a workaround for that then, I haven't played with `babel-node`. I was only answering the question in the context of standalone `node`. – Ruby A. Rose Jun 18 '21 at 21:59
1

This may not help the OP in all cases, but could help others googling for this question. Sometimes it's enough to know if the script is running interactively or not (REPL and any program that is run from a shell).

In that case, you can check for whether standard output is a TTY:

process.stdout.isTTY
djanowski
  • 5,610
  • 1
  • 27
  • 17