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

@venn-lang/io

v0.6.0

Published

The io namespace: standard output, standard error, standard input and the process arguments.

Readme

@venn-lang/io

The io namespace: the standard streams, the terminal behind them, and the process arguments.

A Venn file is a program as often as it is a suite, and a program talks to the outside world through its console. This plugin names the parts of it that need naming, on top of the Console port. Plain print is in the prelude and needs no import; everything else is here.

Install

@venn-lang/io is part of the stdlib the venn CLI and the language server load, so there is nothing to install. A file that uses it says so:

import { io } from "venn/io"

The plugin declares requires: ["io"]. A host that offers no console (the Web Worker host behind the editor offers fs, clock, random, secrets and log) refuses it at load time with VN2010, rather than failing with a TypeError halfway through a run.

Usage

# greet.vn, run with `venn run greet.vn Ada`
import { io } from "venn/io"

const argv = io.args
io.print "arguments: ${argv}"

io.write "name? "
const name = io.readLine
if name == null {
  io.eprint "no name on standard input"
  exit 1
}

io.print "hello, ${name}"

Verbs

Writing

| Verb | Signature | What it does | | --- | --- | --- | | io.print | (...dynamic) -> void | Writes to standard output with a newline. The same as the prelude's print. | | io.write | (dynamic) -> void | Writes to standard output with nothing added after it. | | io.eprint | (dynamic) -> void | Writes to standard error, followed by a newline. |

Reading

| Verb | Signature | What it does | | --- | --- | --- | | io.readLine | () -> string \| null | The next line of standard input, or null at end of input. | | io.readAll | () -> string | Everything left on standard input, which is how a pipe hands over. | | io.readKey | () -> Key \| null | The next keypress, as it is pressed rather than when a line ends. | | io.ask | (string) -> string \| null | Writes a question and reads the answer, which is the two of them at once. |

The terminal

| Verb | Signature | What it does | | --- | --- | --- | | io.size | () -> { columns, rows } \| null | How big it is, or null when the output is not a terminal. | | io.isTerminal | (string) -> bool | Whether "in", "out" or "err" is one. Decides colour, redrawing and whether to ask. | | io.cursor.to | (number, number) -> void | Put the cursor at a column and row, both counting from 1. | | io.cursor.move | (number, number) -> void | Move it from where it is. Negative goes left and up. | | io.cursor.hide / io.cursor.show | () -> void | Hide the caret while redrawing, and put it back. | | io.clearLine | () -> void | Clear the line the cursor is on, and put the cursor at its start. | | io.clear | () -> void | Clear the screen and go to the top left. | | io.args | () -> list<string> | The command-line arguments passed to the script. |

A keypress arrives as { name, text, ctrl, alt, shift }. name is the key spelled out, so up, enter and escape are readable without a table of escape codes, and text is what the key would have typed, empty for the ones that type nothing.

Every screen operation is quietly ignored where there is no terminal, and size answers null there, so one program run interactively and through a pipe is the same program.

io.print takes as many values as you like and joins them with a space. Strings are written as they are; anything else is rendered as JSON, so a map never prints as [object Object].

readLine returns a union with null in its signature, not a bare string: end of input is a real answer and a caller has to face it. args returns a list<string> rather than a bare list, so argv.len and the rest of the list methods type correctly.

Arguments reach io.args from the command line: venn run greet.vn Ada gives ["Ada"].

The Console port

The verbs above are a thin layer over one port, which lives in @venn-lang/contracts because a console is a host capability like the filesystem or the clock, not something this plugin owns.

| | | | --- | --- | | Id | venn.port.console | | Version | 1 | | Requires | io | | Methods | write, writeError, readLine, readAll, readKey, args, size, isTerminal, screen, onResize |

Two implementations ship with it, and both pass the same conformance suite: createNodeConsole from @venn-lang/contracts/node, which writes to Node's real streams and opens stdin on the first read, and createMemoryConsole, which records instead of printing and reads from a scripted input. The fake records screen operations rather than escape codes, so a test says "the cursor went to 3, 5" instead of matching bytes, and resize arranges the one thing a test otherwise cannot. venn run binds the real one, with the command line's arguments; a test binds the recorder and reads back exactly what the program wrote:

import { createMemoryConsole } from "@venn-lang/io";

const console = createMemoryConsole({ input: ["Ada"], argv: ["--name", "ada"] });

console.write(">");
console.out; // ">"
await console.readLine(); // "Ada"
await console.readLine(); // null
console.args(); // ["--name", "ada"]

A fake terminal is a fake console that says it is one:

const console = createMemoryConsole({ size: { columns: 80, rows: 24 }, terminal: ["out"] });

console.size(); // { columns: 80, rows: 24 }
console.screen({ kind: "clearLine" });
console.ops; // [{ kind: "clearLine" }]
console.resize({ columns: 100, rows: 30 }); // every listener hears it

API

| Export | What it is | | --- | --- | | ioPlugin (also the default export) | The PluginDefinition: namespace io, requires the io capability. | | consoleActions | Writing: print, write, eprint. | | inputActions | Reading: readLine, readAll, readKey, ask. | | screenActions | The terminal: its size, whether it is one, the cursor and clearing. | | ConsolePort | The port descriptor, re-exported from @venn-lang/contracts. | | Console | The port's interface (type only). | | createMemoryConsole | The recording implementation, for tests. |

See also