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

@nicia-ai/prose-diff

v0.2.0

Published

Pure, zero-IO markdown block-diff engine: parse markdown into blocks, match block identity across edits and moves, and compute byte-faithful block-level suggestion hunks.

Readme

@nicia-ai/prose-diff

A pure, zero-IO markdown block-diff engine: parse markdown into an ordered list of blocks, match block identity across edits and moves, and compute byte-faithful block-level suggestion hunks.

No filesystem, network, or database access anywhere in this package — markdown strings in, plain data structures out. Extracted from Corpus's document-review engine so both Corpus and other Nicia products can share one implementation instead of drifting copies.

Installation

npm install @nicia-ai/prose-diff

What's in here

  • parseBlocks / parseBlocksWithRanges (block-parse) — decomposes a markdown document into blocks (paragraph, heading, list item, code, table row, blockquote, thematic break, raw HTML) via remark/mdast. List items and table rows are their own blocks, so a comment or suggestion can anchor to a single bullet or row. A leading YAML frontmatter fence is stripped before parsing (see frontmatterLength).
  • matchBlocks (block-match) — content-first structural matching of a block list against its predecessor. Identity follows what a block says, not where it sits, so a relocated block keeps its id. Exact matches carry by content signature; near-matches carry via idf-weighted token similarity (MODIFIED_SIMILARITY_THRESHOLD); everything else is an insert, and every predecessor left unmatched is reported as deleted. This is the anchor lens: built for comment/suggestion anchors that must survive edits and moves.
  • alignBlocks (block-align) — order-preserving alignment for the suggestion diff. Unlike matchBlocks, alignment never reorders: a moved block becomes an explicit delete + insert pair, exactly what git shows. Patience anchoring + bounded LCS/similarity DPs under one shared cell budget keep this fast on real documents.
  • diffSuggestion / diffToHunks / applyHunks (suggestion) — turns a base/proposed markdown pair into an ordered list of block-level Hunks (replace / insert / delete), and reconstructs the post-review document by reverting whichever hunks a reviewer rejected. Byte fidelity is the contract: rejecting every hunk reproduces the base document byte-for-byte, or the diff degrades to one whole-document hunk rather than silently losing part of a proposal.
  • frontmatterLength (frontmatter) — the byte length of a leading ----fenced YAML frontmatter block, or 0 when there is none. The shared boundary both block-parse and suggestion tile the document against.
  • lineDiff / diffSequences (diff) — a small line-level LCS diff for rendering a prose diff (added / removed / same lines), plus the generic sequence-diff engine it's built on (equal(i, j) compares any two indexable sequences, not just lines — the same engine also drives change-flash-style "what moved" detection).

Two-layer pipeline: diffToHunks gives block-granular hunks (a whole paragraph/list-item/etc. replaced, inserted, or deleted); run lineDiff on a hunk's base/proposed text (markdown.slice(hunk.baseStart, hunk.baseEnd) vs hunk.proposedText) to get the line-level highlight within that hunk. Consumers typically pair both rather than picking one.

See src/index.ts for the full exported surface.

Quick start

import { diffToHunks, applyHunks } from "@nicia-ai/prose-diff";

const base = "# Title\n\nOriginal paragraph.";
const proposed = "# Title\n\nEdited paragraph.";

const hunks = diffToHunks(base, proposed);
// [{ ordinal: 1, op: "replace", baseStart: ..., proposedText: "Edited paragraph.", ... }]

const withHunkRejected = applyHunks({ base, proposed, rejected: hunks });
// withHunkRejected === base

Development

pnpm install
pnpm check     # typecheck + lint + format:check + test + build

Releasing

Releases go through Changesets:

pnpm changeset          # describe the change
pnpm version-packages    # bump version + changelog from pending changesets
pnpm release             # build and `changeset publish`

CI publishes via npm's OIDC trusted publishing (.github/workflows/release.yml, mirroring TypeGraph) — no stored npm token, but it requires a trusted publisher configured for the @nicia-ai scope on npmjs.com first. Until that's set up (or for a manual release), the exact one-shot command with local npm publish credentials:

pnpm build && npm publish --access public

License

Apache-2.0 — see LICENSE.