npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

nel

v1.3.0

Published

Node.js Evaluation Loop (NEL): module to run a Node.js REPL session

Downloads

2,216

Readme

Node.js Evaluation Loop (NEL)

NEL is an npm module for running Node.js REPL sessions.

NEL is a spin-off library from IJavascript. This fact explains some of the design decisions in NEL, such as returning results in MIME format, and the functionality provided for completion and inspection of Javascript expressions. See the section on usage for more details.

NEL is used by the following Jupyter kernels:

Main Features

Announcements

  • NEL v1.3.0: API enhancement (added option awaitExecution)
  • NEL v1.2.0: API enhancement (Session#transpile may return a Promise)
  • NEL v1.1.0: API enhancement (added $$.clear({wait}))
  • NEL v1.0.0: Stable API
  • NEL v0.5.6: API enhancement (added $$.input() and onRequest callback)
  • NEL v0.5.5: Accept Promises as output
  • NEL v0.5.4: API enhancement (added $$.display() and onDisplay callback)
  • NEL v0.5: API enhancement (added transpile option)
  • NEL v0.4: API enhancement (added onStdout and onStderr callbacks)
  • NEL v0.3: New API (simplify API by hiding type module:nel~Task)
  • NEL v0.2: API change (removed Session#executionCount)
  • NEL v0.1.1: API enhancement (experimental $$mimer$$ and $$defaultMimer$$)
  • NEL v0.1: Output change (changed function output)
  • NEL v0.0: Initial release

Install

npm install nel

Usage

The documentation generated by JSDoc can be found here.

Hello, World!

// Load `nel` module
var nel = require("nel");

// Setup a new Javascript session
var session = new nel.Session();

// Example of an execution request
// Output:
// { mime: { 'text/plain': '\'Hello, World!\'' } }
var code = "['Hello', 'World!'].join(', ');";
session.execute(code, {
    onSuccess: console.log,
    onError: console.error,
});

Exceptions

// Example of throwing an exception
// Output:
// { error:
//  { ename: 'Error',
//    evalue: 'Hello, World!',
//    traceback:
//     [ 'Error: Hello, World!',
//       '    at evalmachine.<anonymous>:1:7',
//       '    at run ([eval]:182:19)',
//       '    at onMessage ([eval]:63:41)',
//       '    at process.EventEmitter.emit (events.js:98:17)',
//       '    at handleMessage (child_process.js:318:10)',
//       '    at Pipe.channel.onread (child_process.js:345:11)' ] } }
code = "throw new Error('Hello, World!');";
session.execute(code, {
    onSuccess: console.log,
    onError: console.error,
});

stdout and stderr

// Example of use of console.log()
// Output:
// Hello, World!
//
// { mime: { 'text/plain': 'undefined' } }
code = "console.log('Hello, World!');";
session.execute(code, {
    onSuccess: console.log,
    onError: console.error,
    onStdout: console.log,
    onStderr: console.error,
});

onDisplay callback

The Jupyter messaging protocol introduces the concept of display. A display is very much like an execution result. It is associated with an execution request and in protocol version 5.1 and above it can be assigned an ID for subsequent updates. Here's an example of the support provided by NEL:

// Example using onDisplay callback
// Output:
// { mime: { 'text/plain': 'Hello, World!' } }
code = "$$.display().text('Hello, World!');";
session.execute(code, {
    onDisplay: console.log,
});

// Example using a display ID
// Output:
// { display_id: 'test', mime: { 'text/plain': 'Hello, World!' } }
code = "$$.display('test').text('Hello, World!');";
session.execute(code, {
    onDisplay: console.log,
});

onRequest callback and $$.input(options, callback)

The Jupyter messaging protocol defines an stdin socket, so that a kernel can request an input from the user. NEL defines $$.input(options, callback) to create such a request.

Here are two examples (first one passing a callback to $$.input; second one using a Promise returned by $$.input()):

// Example passing a callback to $$.input()
// Output:
// { mime: { 'text/plain': '\'opensesame\'' } }
code = "$$.input({prompt:'?', password: true}, function(error, reply) {$$.done(reply)});";

session.execute(code, {
    onRequest: function(request, onReply) {
        assert(request.input.prompt === "?");
        assert(request.input.password === true);

        onReply({input: "opensesame"});
    },
    onSuccess: console.log,
});

// Example using the Promise returned by $$.input()
// Output:
// { mime: { 'text/plain': '\'opensesame\'' } }
code = "(function($$) {$$.input({prompt:'?', password: true}).then($$.done);})($$);";

session.execute(code, {
    onRequest: function(request, onReply) {
        assert(request.input.prompt === "?");
        assert(request.input.password === true);

        onReply({input: "opensesame"});
    },
    onSuccess: console.log,
});

onRequest callback and $$.clear(options)

The Jupyter messaging protocol defines the message clear_output for kernels to request the output of a cell to be cleared. NEL provides $$.clear(options) to implement such a request.

Here's an example showing the use:

// Example using $$.clear(options)
// Output:
// { clear: { wait: true } }
code = "$$.clear({wait: true});";

session.execute(code, {
    onRequest: console.log
});

MIME output

A session may return results in MIME formats other than 'text/plain'.

// HTML example
// Output:
// { mime: { 'text/html': '<div style=\'background-color:olive;width:50px;height:50px\'></div>' } }
code = "$$html$$ = \"<div style='background-color:olive;width:50px;height:50px'></div>\";";
session.execute(code, {
    onSuccess: console.log,
    onError: console.error,
});

// SVG example
// Output:
// { mime: { 'image/svg+xml': '<svg><rect width=80 height=80 style=\'fill: orange;\'/></svg>' } }
code = "$$svg$$ = \"<svg><rect width=80 height=80 style='fill: orange;'/></svg>\";";
session.execute(code, {
    onSuccess: console.log,
    onError: console.error,
});

// PNG example
code = "$$png$$ = require('fs').readFileSync('image.png').toString('base64');";
session.execute(code, {
    onSuccess: console.log,
    onError: console.error,
});

// JPEG example
code = "$$jpeg$$ = require('fs').readFileSync('image.jpg').toString('base64');";
session.execute(code, {
    onSuccess: console.log,
    onError: console.error,
});

// MIME example
code = "$$mime$$ = {\"text/html\": \"<div style='background-color:olive;width:50px;height:50px'></div>\"};";
session.execute(code, {
    onSuccess: console.log,
    onError: console.error,
});

Promises are accepted as output

When the result of an execution request is a Promise, NEL enables asynchronous execution automatically and waits for the Promise to resolve:

// Example returning a Promise
// Output:
// { mime: { 'text/plain': '\'Hello, World!\'' } }
code = "Promise.resolve('Hello, World!');";

session.execute(code, {
    onSuccess: console.log,
});

Generate a completion list

NEL can parse simple Javascript variable expressions and generate a list of completion options:

session.complete(
    "set",     // code
    3,         // cursorPos
    {
        onSuccess: console.log,
        onError: console.error,
    }
);

// Output:
// { completion:
//    { list: [ 'setImmediate', 'setInterval', 'setTimeout' ],
//      code: 'set',
//      cursorPos: 3,
//      matchedText: 'set',
//      cursorStart: 0,
//      cursorEnd: 3 } }

Note that the cursor position can be located anywhere within the Javascript code:

session.complete(
    "set",     // code
    2,         // cursorPos
    {
        onSuccess: console.log,
        onError: console.error,
    }
);

// Output:
// { completion:
//    { list: [ 'setImmediate', 'setInterval', 'setTimeout' ],
//      code: 'set',
//      cursorPos: 2,
//      matchedText: 'se',
//      cursorStart: 0,
//      cursorEnd: 3 } }

Inspect an expression

NEL can parse simple Javascript variable expressions and inspect their value:

code = "var a = [1, 2, 3];";
session.execute(code, null, onError);
session.inspect(
    code,      // code
    5,         // cursorPos
    {
        onSuccess: console.log,
        onError: console.error,
    }
);

// Output:
// { inspection:
//    { string: '[ 1, 2, 3 ]',
//      type: 'Array',
//      constructorList: [ 'Array', 'Object' ],
//      length: 3,
//      code: 'var a = [1, 2, 3];',
//      cursorPos: 5,
//      matchedText: 'a' } }

NEL can also provide relevant documentation (currently only available for Javascript builtins):

session.inspect(
    "parseInt", // code
    8,          // cursorPos
    {
        onSuccess: console.log,
        onError: console.error,
    }
);

// Output:
// { inspection:
//    { string: '[Function: parseInt]',
//      type: 'Object',
//      constructorList: [ 'Function', 'Object' ],
//      length: 2,
//      code: 'parseInt',
//      cursorPos: 8,
//      matchedText: 'parseInt' },
//   doc:
//    { description: 'The parseInt() function parses a string argument and returns an integer of the specified radix (the base in mathematical numeral systems).',
//      url: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt',
//      usage: 'parseInt(string, radix);' } }

Callbacks beforeRun and afterRun

var beforeRun = function() { console.log("This callback runs first"); }
code = "'I run next'";
var afterRun = function() { console.log("This callback runs last"); }
session.execute(code, {
    onSuccess: console.log,
    onError: console.error,
    beforeRun: beforeRun,
    afterRun: afterRun,
});

// Output:
// This callback runs first
// { mime: { 'text/plain': '\'I run next\'' } }
// This callback runs last

Contributions

First of all, thank you for taking the time to contribute. Please, read CONTRIBUTING.md and use the issue tracker for any contributions: support requests, bug reports, enhancement requests, pull requests, ...

TODO

  • Add tests for customising output
  • Add Node.js documentation