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

@yuhere/js-readline

v1.0.0

Published

readline modules to read lines from a readable stream.

Downloads

38

Readme

@yuhere/js-readline

ES-only TypeScript library for reading lines from web-platform input sources — Response, ReadableStream<Uint8Array>, Blob, and File.

  • Forward & backward iteration
  • Around mode — surrounding-line context for editors/viewers
  • Abort control — cancel mid-stream
  • Node.js & browser — single ESM bundle

Installation

npm install @yuhere/js-readline

Quick start

Forward (top → bottom)

import { readline_fw } from "@yuhere/js-readline";

const [ctrl, lines] = readline_fw(new Blob(["hello\nworld"]));
for await (const { line, lineNo } of lines) {
    console.log(lineNo, line); // 1 hello, 2 world
}

Backward (bottom → top)

import { readline_bw } from "@yuhere/js-readline";

const [ctrl, lines] = readline_bw(new Blob(["first\nsecond\nthird"]));
for await (const { line, lineNo } of lines) {
    console.log(lineNo, line); // -1 third, -2 second, -3 first
}

Around mode (with context)

import { around_lines_fw } from "@yuhere/js-readline";

const [ctrl, around_lines, gen] = await around_lines_fw({
    input: new Blob(["line1\nline2\nline3\nline4\nline5"]),
    AROUND_LIMIT: 10,
});

for await (const { line, lineNo } of gen) {
    const ctx = around_lines(-1, 1); // [prev, current, next]
    console.log(lineNo, line, ctx);
}

Streaming from fetch

const res = await fetch("https://example.com/data.ndjson");
const [ctrl, lines] = readline_fw(res);
for await (const { line } of lines) {
    const data = JSON.parse(line);
    if (data.done) ctrl.abort();
}

vs Node.js built-in readline

Bottom line: Node.js readline is 3–10× faster (C++ implementation), but only works in Node.js, only reads forward, and doesn't provide byte offsets or context windows. Choose based on your needs.

Feature comparison

| | @yuhere/js-readline | Node.js readline | |---|---|---| | Runtime | Browser + Node.js | Node.js only | | Direction | Forward & backward | Forward only | | Around mode | ✓ sliding window context | — | | Abort control | ✓ AbortController | ✓ close() | | Byte locations | ✓ {start, end} per line | — | | Input types | Response, ReadableStream, Blob, File | Node.js Readable streams | | Performance | 60–500 MB/s (pure JS) | 150–4,700 MB/s (C++) | | Lines returned | {line, lineNo, loc, size} | string only | | Pause / resume | Via abort + re-create | ✓ built-in | | Dependencies | Zero | Built into Node.js |

When to use each

Use @yuhere/js-readline when you need:

  • Browser support (files, fetch responses, Blob APIs)
  • Backward line reading (tail -r, log viewers)
  • Around-mode context (code editors, grep -C, source viewers)
  • Precise byte offsets for each line
  • A consistent API across Node.js and the browser

Use Node.js readline when you need:

  • Maximum throughput on large files (Node.js only)
  • Pause/resume during iteration
  • The standard, built-in solution with zero dependencies

Performance snapshot

10 MB file, 200 B/line, Stream input — npm run bench:vs-node

| | MB/s | lines/s | |---|---|---| | js-readline | ~141 MB/s | ~735 K | | Node.js readline | ~1,549 MB/s | ~8.1 M | | Ratio | 0.1× | 0.1× |

The gap comes from three JS-level costs Node.js avoids in C++:

  1. TextDecoder.decode() called per line (JS→native overhead × N)
  2. Uint8Array.slice() allocates new memory per line (GC pressure)
  3. Async generator yield per line + chunk boundary handling

Full benchmark suite: npm run bench

API

readline_fw(input, options?)

Read lines top to bottom. Returns [AbortController, AsyncGenerator].

| Param | Type | Description | |---|---|---| | input | Response \| ReadableStream<Uint8Array> \| Blob \| File | Source to read from | | options.encoding | string | TextDecoder encoding (default "utf-8") | | options.controller | AbortController | Reuse an existing controller | | options.size | number | Known byte size (ignored for Blob/File; NaN when unknown) |

readline_bw(input, options?)

Read lines bottom to top. Only accepts Blob | File. Returns [AbortController, AsyncGenerator]. Line numbers are negative (-1 = last line).

| Param | Type | Description | |---|---|---| | input | Blob \| File | Source to read from | | options.encoding | string | TextDecoder encoding (default "utf-8") | | options.controller | AbortController | Reuse an existing controller |

around_lines_fw(options)

Forward around-mode. Returns Promise<[AbortController, AroundLinesFunc, AsyncGenerator]>.

| Option | Type | Default | Description | |---|---|---|---| | input | Response \| ReadableStream \| Blob \| File | — | Source to read from | | AROUND_LIMIT | number | 30 | One-sided look-behind/ahead bound (clamped ≥ 0) | | encoding | string | "utf-8" | TextDecoder encoding | | size | number | NaN | Known byte size |

around_lines_bw(options)

Backward around-mode. Only accepts Blob | File. Same options as around_lines_fw (except size). Line numbers are negative.

around_lines(before?, after?)

The context-lookup function returned by around_lines_fw / around_lines_bw. Returns a string[] slice of buffered lines relative to the current iteration position.

| Call | Result | |---|---| | around_lines() | All buffered lines | | around_lines(-1, 0) | [prev, current] | | around_lines(0, 1) | [current, next] | | around_lines(-1, 1) | [prev, current, next] | | around_lines(0) | [current, ..., end] | | around_lines(-1) | [prev, ..., end] |

Throws if after < before.

Yielded value — StreamReadlineValue

Each line is yielded as an object:

{
    loc: Location;   // {start: number, end: number} — byte range including newline
    size: number;    // total input bytes (NaN if unknown)
    lineNo: number;  // 1-based: positive forward, negative backward
    line: string;    // decoded text with trailing \r?\n removed
}

Types

| Export | Description | |---|---| | StreamReadlineValue | Shape of each yielded line | | StreamReadlineResult | [AbortController, AsyncGenerator] | | Location | {start: number, end: number} byte range | | ReadlineOptions | Shared options type (encoding, controller) | | AroundLinesFunc | Signature of the around_lines() callback | | AroundLinesResult | [AbortController, AroundLinesFunc, AsyncGenerator] | | LinesAroundFwOptions | Options for around_lines_fw | | LinesAroundBwOptions | Options for around_lines_bw |

License

MIT