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

@cutticat/md-url-map

v2.0.0

Published

Map every URL destination in Markdown through a callback

Readme

@cutticat/md-url-map

Rewrite URL destinations in Markdown through a mapper. Relative links stay in git; pack turns them into GitFlic, GitHub, or GitLab URLs for npm. Inline images point at the raw file. Links and reference definitions stay on the blob page.

Table of Contents

Overview

map(markdown, mapper) walks [text](href), images, and reference definitions with micromark and calls mapper for each destination. Return the same string to leave it unchanged. Replacements are written as <url>. Code spans, fences, and the rest of the file stay as they are.

Compose with when(isRelative, toGitFlic({ ... })) so only file-relative hrefs (./a.md, docs/a.md) are rewritten. A link becomes a blob URL. An inline image (![alt](./logo.png)) becomes a raw URL, which npmjs can display. Hash, /rooted, //host, and https: are left alone. Other predicates: isAbsolute, isHash, isRootRelative, isProtocolRelative. toBase({ base }) resolves like a browser: new URL(href, base). The destination type is ignored there.

The md-url-map CLI is the same composition: map for one file (--host or --base), pack for a prepack hook that reads package.json repository and rewrites README.md.

Installation

pnpm i @cutticat/md-url-map

CLI

After install, the md-url-map binary is on PATH via pnpm exec. In this repository, pnpm run md-url-map map ….

map

Rewrite relative destinations in one file. Default: stdout.

Pass --base or --host, not both. --base resolves relative hrefs against a document URL (WHATWG new URL(href, base)). --host writes git blob URLs for links and raw URLs for inline images.

--file is the Markdown path from the git root (inferred from .git when you pass a real path). Required when reading stdin with --host. Unused with --base.

md-url-map map README.md --base https://example.com/docs/README.md
md-url-map map README.md --host gitflic --owner cutticat-npm --project uuids
md-url-map map README.md --host gitflic --owner cutticat-npm --project uuids -i
md-url-map map README.md --host github --owner acme --repo app -o out.md
md-url-map map README.md --host gitlab --project-path group/app --ref v1.0.0
cat README.md | md-url-map map - --file README.md --host gitflic --owner o --project p

| Flag | Meaning | | --- | --- | | --base | Document URL for relative destinations | | --host | gitflic, github, or gitlab | | --owner | GitFlic / GitHub owner | | --project | GitFlic project slug | | --repo | GitHub repository name | | --project-path | GitLab group/project | | --ref | Git ref (default main) | | --file | Path of this Markdown file from the git root | | --origin | Host origin (self-hosted) | | -o, --output | Write a file instead of stdout | | -i, --in-place | Overwrite the input file |

pack

Read package.json repository in the current directory (or -C), rewrite README.md in place. Infers GitFlic / GitHub / GitLab from the URL. file for URL resolve is the README path from the git root (walks up to .git).

repository.url may be https://, git+https://, ssh://, git+ssh://, git://, or git@host:path. SSH and git:// remotes get an https:// origin. GitFlic HTTPS is /project/{owner}/{project}; the SSH clone [email protected]:owner/project works too.

An inline image becomes a raw URL on the same origin:

  • GitHub: /{owner}/{repo}/raw/{ref}/{path}
  • GitLab: /{project}/-/raw/{ref}/{path}
  • GitFlic: /project/{owner}/{project}/blob/raw?branch={ref}&file={path}

A link to the same file stays a blob URL. So does a reference definition ([id]: ./logo.png): one definition is shared by links and images.

Use from prepack. Restore the working tree in postpack yourself (git checkout -- README.md). This package does that for its own README.

md-url-map pack
md-url-map pack -C ./packages/plugin --ref main

| Flag | Meaning | | --- | --- | | -C, --directory | Package directory (default .) | | --readme | README path relative to the package (default README.md) | | --ref | Git ref (default main) | | --file | Override the git-root-relative Markdown path | | --origin | Override origin from the repository URL | | --host | Force gitflic, github, or gitlab when the host is unknown | | -q, --quiet | Do not print the rewritten path |

Quick start

import { isRelative, map, toBase, toGitFlic, when } from "@cutticat/md-url-map"

map(
  markdown,
  when(
    isRelative,
    toGitFlic({
      owner: "cutticat-npm",
      project: "uuids",
      ref: "main",
      file: "README.md",
    })
  )
)

map(markdown, when(isRelative, toBase({ base: "https://example.com/docs/README.md" })))
import { map } from "@cutticat/md-url-map"

map("[site](https://old.example)", href =>
  href === "https://old.example" ? "https://new.example" : href
)
// [site](<https://new.example>)

API

  • map(markdown, mapper) — walk destinations, return a new string
  • when(predicate, mapper) — run mapper only when predicate is true
  • isAbsolute(href) — scheme URLs (https:, mailto:)
  • isHash(href) — hash-only (#overview)
  • isProtocolRelative(href) — protocol-relative (//cdn.example/x)
  • isRelative(href) — file-relative destinations (./a.md, docs/a.md)
  • isRootRelative(href) — root-relative (/docs/a.md)
  • toBase({ base }) — new URL(href, base) (document URL)
  • toGitFlic({ owner, project, ref, file, origin? })
  • toGitHub({ owner, repo, ref, file, origin? })
  • toGitLab({ projectPath, ref, file, origin? })
  • HrefType — "image" for ![alt](href), "other" for links and definitions
  • HrefMapper — (href, type) => string
  • HrefPredicate — (href, type) => boolean

file is the Markdown path from the git root (README.md, packages/plugin/README.md).

Replacements use source offsets. Surrounding Markdown is not reformatted.

Documentation

Requirements

  • Node.js >= 22.18.0
  • pnpm >= 10.17.0
  • TypeScript >= 5.9.0