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

@weasel-js/bidi

v1.13.0

Published

The Unicode Bidirectional Algorithm (UAX #9) for weasel: embedding levels, reordering and mirroring. Plain data in, plain data out; no renderer and no scene graph.

Readme

@weasel-js/bidi

The Unicode Bidirectional Algorithm (UAX #9), as a standalone leaf: code points and a direction in, embedding levels and a visual order out.

No fonts, no glyphs, no canvas, no DOM, and no dependencies. Nothing else in weasel depends on this package — a text layout that wants bidi is handed an implementation of BidiEngine, and one that isn't lays out in logical order.

import { analyze, reorder } from '@weasel-js/bidi';

const codePoints = [...'שלום 25'].map((c) => c.codePointAt(0)!);
const paragraph = analyze(codePoints);        // 'auto' — first-strong, so RTL here
const { order } = reorder(paragraph, 0, codePoints.length);
// `order` indexes codePoints in display order; the digits stay 2 then 5.

Two calls because the algorithm splits at exactly one place. analyze is per paragraph; reorder is per line, because L1 resets trailing whitespace against the end of a line rather than the end of a paragraph. Wrap between them, and one analysis serves every line.

mirror(cp) is L4, applied at paint time against a character's resolved level — the same code point mirrors in one run and not in another. baseLevel(paragraph) is the level the paragraph reads at, which under 'auto' is what its first strong character decided.

Giving it to weasel's text

import { bidi } from '@weasel-js/bidi';
import { registerBidi } from '@weasel-js/core';

registerBidi(bidi);   // once, at startup

Every text layout after that reorders right-to-left text: what a canvas paints, picks, and places a caret in, and what measureTextBounds and textToPath report.

What this does not do

Ordering only. Arabic still renders unjoined: joining forms are OpenType GSUB substitutions, not a reordering, and belong to a shaping engine. Hebrew, Divehi and the other non-joining right-to-left scripts are complete with bidi alone.

Conformance

Verified against Unicode's own data, in full — all 91,707 cases of BidiCharacterTest.txt and all 490,846 of BidiTest.txt. Character data is generated by npm run gen:bidi-tables; the Unicode version it was built from is exported as UNICODE_VERSION.