OhmJS

@ohmjs.org

A user-friendly parsing toolkit for JavaScript and TypeScript ∙ https://ohmjs.org

One more time — I'm looking for new consulting clients. Some ways I can help: ∙ Fractional tech leadership (tackling "leadership debt" in small eng orgs) ∙ Full-stack, 0 to 1 projects ∙ Language design & impl (eg with @ohmjs.org) ∙ JavaScript/TypeScript perf (🔁 appreciated)

Patrick Dubroy@dubroy.com · 5mo ago

Also I finally put together a consulting/ page, for anyone who's interested in working with me. dubroy.com/consulting/ Did I mention I still have availability this year? 😇

Consulting
I do technical advising and freelance development for companies big and small.

Some recent examples:

Part-time advising for a small startup, doing regular 1-on-1s with the CTO and selected ICs. Advised on technical architecture and team issues, and helped them hire a Head of Engineering and their first Staff Engineer.
Worked with HCI pioneer Michel Beaudouin-Lafon and his research group to build a fully incremental processing pipeline for Asciidoc with Ohm.
For a research group investigating parametric CAD/CAE systems, implemented a GPU-based interpreter (in Rust and WGSL) for rendering implicit surfaces.
For engineering projects, I’m especially interested in work where I can combine my deep systems expertise with frontend development and UX work.

Whoah. Today we discovered that ohm-js is now a "high-impact" NPM package (>1M downloads/week). The mystery was: why? Turns out it's now a transitive dependency of the Vercel CLI, via pip-requirements-js, an Ohm-based package for parsing requirements.txt files: github.com/Twixes/pip-r...

Line chart showing weekly downloads for the npm package "ohm-js" from February 28, 2025 to February 26, 2026. The graph displays relatively flat growth at around 200,000 weekly downloads for most of the year, then shows dramatic exponential growth starting in late January 2026, skyrocketing from approximately 200,000 to 1.8 million weekly downloads by late February 2026. The y-axis shows weekly downloads ranging from 0 to 1.8M, and the x-axis shows dates with major tick marks every few months

Take a look if you're interested in using Ohm to compile to #Wasm. (This is the same library we use in the new Ohm v18 beta that compiles grammars to Wasm.)

WebAssembly from the Ground Up@wasmgroundup.com · 5mo ago

We've released a new version of @wasmground/emit — the small, simple #Wasm 1.0 "assembler library" for JS/TS, which we build up piece by piece in our book. The headline feature: proper TypeScript types! Give it a spin and let us know what you think: www.npmjs.com/package/@was...

import * as w from "@wasmgroundup/emit";

const mod = w.module([
  w.typesec([w.functype([w.valtype.i32, w.valtype.i32], [w.valtype.i32])]),
  w.funcsec([w.typeidx(0)]),
  w.exportsec([w.export_("add", w.exportdesc.func(w.funcidx(0)))]),
  w.codesec([
    w.code(
      w.func(
        [],
        w.expr([
          [w.instr.local.get, ...w.i32(0)],
          [w.instr.local.get, ...w.i32(1)],
          w.instr.i32.add,
        ]),
      ),
    ),
  ]),
]);

const { instance } = await WebAssembly.instantiate(w.flatten(mod));
const { add } = instance.exports as { add: (a: number, b: number) => number };
console.log(add(1, 2)); // 3

Published v17.3.0 yesterday, with a couple small improvements to the typings and a bug fix related to matching letters outside the BMP (basic multilingual plane): github.com/ohmjs/ohm/re... Last release of 2025 (hopefully 🤞)…watch for a new major release early next year!

Release Ohm v17.3.0 · ohmjs/ohm

Browser bundles: ohm.js • ohm.min.js New features [d957ac7] typings: #494 - Typescript MatchResult object incomplete [e1b8225] typings: add FailedMatchResult / SucceededMatchResult [891b6d8] feat:...

github.com

Just added an example to the Ohm repo of implementing something like Zed's SumTree. (aka "monoid-cached trees" if you want to sound clever) Full example here: github.com/ohmjs/ohm/bl...

Screenshot of the following code:

// In abstract algebra, a _monoid_ is a set (or a data type) that has
// (a) a "combine" operation that's associative, i.e. (a + b) + c = a + (b + c)
// (b) an identity or neutral element.
// This is our identity element…
const LOC_IDENTITY = {line: 0, col: 0};

// …and this is our "combine" operator.
function sumLocations(a, b) {
  return {
    line: a.line + b.line,
    // If `b` has more than one line, we can ignore `a.col`.
    col: b.line > 0 ? b.col : a.col + b.col,
  };
}

function compareLocations(a, b) {
  return a.line - b.line || a.col - b.col;
}

const semantics = g.createSemantics();

// A helper operation to get the "size" of a node, such that
// endLoc = sumLocations(startLoc, size).
semantics.addAttribute('_size', {
  _default(...children) {
    return children.reduce((acc, node) => sumLocations(acc, node._size), LOC_IDENTITY);
  },
  _terminal() {
    const lines = this.sourceString.split('\n');
    return {
      line: lines.length - 1,
      col: lines.at(-1)?.length || 0,
    };
  },
});
Patrick Dubroy@dubroy.com · 8mo ago

Stumbled across it in Raph Levien's resources for learning compute shaders: notes.billmill.org/programming/... Never realized how many things (including a lot of text processing) can be expressed as scan / all-prefix-sums. Eg see "Zed Decoded: Rope & SumTree" zed.dev/blog/zed-dec...

Hey everyone, just FYI: After investigating, we do *not* believe that ohm-js, or any other package under the @ ohmjs namespace, is affected by the Shai-Hulud worm or any of the recent npm supply chain attacks.

Pretty pleased with the ergonomics of the Wasm (macro-)assembler in @ohmjs.org. It's built on the low-level assembler lib we created for @wasmgroundup.com, but has some nice higher-level features, including labeled breaks. I'm particularly proud of the idea to put the block label at the end. 😊

A code screenshot showing a TypeScript/JavaScript function called ⁠wrapTerminalLike that generates WebAssembly (WASM) code. The code contains:  • A function definition that takes a ⁠thunk parameter  • Assembly code generation using an ⁠asm object with methods like ⁠block(), ⁠localSet(), ⁠break(), etc.  • A ⁠break statement that references a label called ⁠'_success' (highlighted with a pink arrow and annotation "This...")  • A label definition for ⁠'_success' at the bottom (highlighted with a red arrow and annotation "...goes here")  • Additional assembly operations like ⁠newTerminalNodeWithSavedPos(), ⁠updateLocalFailurePos(), and ⁠setRet()  The pink annotations with arrows illustrate the control flow relationship between the break statement and its corresponding label, showing how the break jumps to the ⁠'_success' label.

A few different Ink & Switch projects have used Ohm…here's the latest one. From @alexwarth.bsky.social (co-creator of Ohm) and @geoffreylitt.com (who made Wildcard, one of our all-time favourite Ohm-powered projects)

Alex Warth@alexwarth.bsky.social · last yr.

What if a spreadsheet cell could hold multiple values at the same time? That's the idea behind Ambsheets, a project I've been working on w/ @geoffreylitt.com at @inkandswitch.com. It's a new spreadsheet that makes it easier for you to explore many possibilities simultaneously. 1/2

Ever wanted to use Ohm from another language? Go, Python, Rust? See the brand new, experimental support for compiling Ohm grammars to Wasm: github.com/ohmjs/ohm/d... It wasn't the main goal, but it also appears to be a perf win — parsing is about 10x faster on real-world grammars (e.g. ES5).

A couple months ago, I started prototyping a new feature: the ability to compile an Ohm grammar to WebAssembly, so that it can be used from languages other than JS. You can find more background (use cases and implementation details) in #503.  The MVP is complete, and this feature is now available for early testing (with some limitations). We're very interested to get feedback and hear what uses cases people have for this.  Although it wasn't the main motivation for this work, early benchmarks are showing ~10x improvement in parse times. Take this with a grain of salt — since the implementation isn't yet complete, it's hard to know what the final performance will look like. But it looks like this will be a significant performance win for real-world grammars!

Hey folks, we had another Cloudflare ⇆ GitHub SSL issue which meant the web site was down for about an hour. Thanks for @onlineornot.com we found out pretty quickly, and it should be fixed now! And we'll be getting rid of Cloudflare so hopefully we'll be rid of this problem for good 🤞

Wondering if the book is *practical*? I'm currently using the helper library extracted from the book for a new @ohmjs.org feature which will allow you to compile Ohm grammars to Wasm. This will make it possible to use Ohm grammars from Go, Python, etc. Details here 👉 github.com/ohmjs/ohm/is...

Patrick Dubroy@dubroy.com · last yr.

btw what I'm using here is the "assembler library" that we construct bit by bit in @wasmgroundup.com. It's also available as a standalone NPM package: www.npmjs.com/package/@was... There's not yet much documentation (outside of the book), but we'll work on that soon!