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 🙏

© 2026 – Pkg Stats / Ryan Hefner

choir

v0.0.8

Published

An enhanced node REPL

Downloads

11

Readme

Interactive Node.js

Modified REPL to behave like ipython.

Currently only works with node v4

Run Magic

%run path/to/file

This is modeled after the %run magic of ipython.

It differs from require in the following ways:

  • The file will execute in shell and it's namespace will be merged into global.
  • The file will act as if it's located in the choir startup directory. require will be anchored there.
  • The executions will not cache. Each call will re-execute the script.

.html executing

In addition to running .js files, you may also run a .html file. This will do following:

  1. Create an mepty jsdom window. This is slightly modified with a XMLHttpRequest that will grab the file locally.
  2. Set the document.innerHTML to the contents of the .html file.
  3. Wait for the window to gain new varialbes. This part is done via a simple function that checks via setTimeout.
  4. Take the changed variables from window and bring them to the REPL global context.
  5. Set the internal webserver to output the rendered html minus the script tags (as those are running in the internal jsdom and are not required for a client browser).

The above steps have the effect of running an html page as if it were the browser, and allowing you to modify the dom from the choir shell. Advantages over just editing a script and refreshing a browser page:

  • Allows you to stay in CLI with the choir shell. For me it's vim/tmux which is infintely more effective than using the browser javacript console.
  • Because we bring the html global into the shell, we can modify the dom and see the rendered output by refreshing the page.
  • We can also %run additional scripts that modify the dom. As long as we don't run another html file, our DOM will be persistent.

Workflow

In general there are 3 different workflows.

  1. The first is purely node.js. If you're not touching anything that outputs to the browser, then you obviously have no need for the html execution. Note that using something like d3 in node.js implicitly creates its own jsdom objects in some way doesn't differ from the html execution approach. Though, it's still supported and you can output the standalone d3 html via the _http_callback.
  2. Executing an html file and playing with it via choir. This appears to be the most useful. Like I said above, some node.js modules are implicitly creating the DOM. Note, that all of the javascript logic runs in choir. If you were to try to Rounded Rectangle you would get the current frame on each refresh and not the animation tiself.
  3. Straight html. The internal webserver will also serve up .html files. Because it is rooted at the choir startup directory, it should replicate the choir XHR logic. Meaning that if you have a request for data.json that lives in the same directory, the internal html execution will grab that file locally, while the straight html will make a webrequest that grabs the same file. So, that means that an .html file should output the same DOM when accessed both ways.

Seprating DOM environments

You will notice that there is a strict separation between whether scripts execute in the browser or internally. This means that you will never animation/callbacks via html execution because we strip the javascript. It is possible to keep choir from stripping a script by adding an choir-keep="true" attribute. However, this would require you to completely separate out your event binding/selection from your data manipulations.

So far I've found that to be too laborious.

Internal Web Server

When you start up choir, the kernel will also startup a webserver hosted at port 8889. This will output the DOM of the last run html file. You may customize the output by creating a `_http_callback' function that lives in the shell namespace.

The server will also act like a normal webserver for pathed urls. The webroot will be the choir startup directory. So if you started up choir in its demo directory, `http://localhost:8889/brush/brush.html' would show you the Brush demo.


Brush Demo

%run ./brush.html

var data = focus.select('path').datum()
var l = [data[10].date, data[25].date]
brush.extent(l)
brushed()
// redraw the extent rect
var ex = x2(l[0]);
var width = x2(l[1]) - ex;
var extent = context.select('g.x.brush rect.extent');
extent.attr('x', ex);
extent.attr('width', width);

This run the vanilla brush demo. It then modifies the brush extent and calls the handler that modifies the top chart. It also redraws the rect which is not handled by brushed().

Brushed chart

Tips

Place the following in your .vimrc

autocmd FileType javascript map <buffer> <S-r> :w<CR>:!tmux send-keys -t choir "\%run %:p" enter<CR><CR>

Pressing Shift + R while editing a .js file in vim will execute the file in a tmux session named choir.

Future Plans

  • ls, pwd, cd, etc filesystem magics