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

@verifyhash/slugify-lite

v0.1.1

Published

Zero-dependency, zero-network string-to-URL-slug library for Node.js: Latin-1/accent transliteration via a pinned in-repo map, custom separator, word-boundary maxLength truncation, and custom replacement overrides.

Downloads

41

Readme

slugify-lite

A tiny, zero-dependency, zero-network Node.js library that turns an arbitrary string into a clean URL slug: "Héllo, World!""hello-world". One CommonJS file (index.js), no install step, no I/O, no runtime require of anything — drop it into any project and require it.

Install

npm install @verifyhash/slugify-lite

Published as @verifyhash/slugify-lite; source lives in the verifyhash/libs monorepo. Zero runtime dependencies — you can also vendor the folder directly.

Who it's for

JavaScript/Node developers who need slugs for URLs, filenames, anchor IDs, or database keys and want a small, auditable, single-file helper instead of pulling in a larger dependency graph. It covers the everyday Western-European case (accented Latin letters like é, ü, ñ, ß, ø, æ) with a pinned, in-repo character map — no lookup tables downloaded at runtime, no transitive packages. If you already reach for slugify or @sindresorhus/slugify but want zero deps and full control over the map, this is that.

Install / use

No install — copy index.js, or require it directly:

const slugify = require('./index.js');

slugify('Héllo, World!');                 // 'hello-world'
slugify('Crème brûlée');                  // 'creme-brulee'
slugify('Straße');                        // 'strasse'   (ß -> ss)

// custom separator
slugify('Hello World', { separator: '_' }); // 'hello_world'

// preserve case
slugify('CamelCase API', { lowercase: false }); // 'CamelCase-API'

// truncate to a max length on a WORD boundary (never mid-word)
slugify('The quick brown fox', { maxLength: 15 }); // 'the-quick-brown'
slugify('The quick brown fox', { maxLength: 13 }); // 'the-quick'

// custom replacements, merged OVER the built-in map (raw-char match)
slugify('100% cotton & wool', {
  replacements: { '%': ' percent ', '&': ' and ' }
}); // '100-percent-cotton-and-wool'

API

slugify(input, options?) → string

input is coerced with String(); null/undefined return ''.

| option | type | default | meaning | | -------------- | --------- | ------- | ----------------------------------------------------------------------------------------- | | separator | string | '-' | Character(s) used to join words. May be multi-character or ''; matched literally. | | lowercase | boolean | true | Lowercase the result. Set false to preserve case (transliteration still happens). | | maxLength | number | — | Max output length. Truncated on a word boundary — never mid-word, never a trailing separator. | | replacements | object | — | Single-char → string map, merged over the built-in map. Matched against the raw character (before lowercasing). |

Pipeline, in order: (1) transliterate each character (custom replacements win over the built-in map, then the built-in map, else the char passes through); (2) lowercase unless lowercase: false; (3) collapse every run of non-ASCII- alphanumeric characters ([^A-Za-z0-9]+) to a single separator, which strips punctuation, whitespace, and any unmapped characters; (4) trim leading/trailing separators; (5) if maxLength is set, keep whole words while the running slug (words joined by separator) stays <= maxLength.

The module also exposes slugify.slugify, slugify.default (both the same function), and slugify.charMap — a frozen copy of the built-in map for inspection.

Limits (please read — this is the honest part)

  • It only romanizes what the built-in map covers. The map is a small, hand-maintained table of common accented/Latin-1 and a few Latin-Extended characters (roughly à á â ã ä å ā ă ą æ ç ć č ð è é ê ë ē ę ě ñ ń ň ø ō œ ß þ ù ú û ü ū ů ý ÿ ž … plus their uppercase forms). It is not Unicode-complete and does not do context-aware romanization.
  • Non-Latin scripts are stripped, not transliterated. Cyrillic (Москва), Greek, Arabic, Hebrew, Hangul, and CJK (日本語) are not in the map, so step 3 removes them. slugify('日本語 test')'test', and slugify('日本語')''. If you need Chinese→pinyin, Cyrillic→Latin, or Greek→Latin romanization, use a dedicated transliteration library — that is deliberately out of scope here.
  • Emoji and symbols are dropped unless you supply a replacements entry for them (e.g. { '&': ' and ' }).
  • maxLength never splits a word. If the very first word is longer than maxLength, the result is '' (there is no whole word that fits). It counts the separator length between words, but does not hyphenate or ellipsize.
  • Custom replacements match the raw character, before lowercasing — so to override ø supply the lowercase key 'ø'; an uppercase 'Ø' in the input is handled by the built-in uppercase map entry unless you add 'Ø' yourself.
  • No collision avoidance / uniqueness. Two different inputs can slug to the same string ('Café!' and 'café' both → 'cafe'). If you need unique slugs, dedupe at the call site.

Running the tests

One command, Node's built-in assert only — no test runner, no dependencies:

node test/index.test.js

It prints slugify-lite: all N tests passed. and exits 0 on success. The suite covers accented→ASCII transliteration (including ß→ss, æ→ae), punctuation/whitespace collapsing, custom separators, non-Latin/CJK/emoji passthrough behavior, maxLength word-boundary truncation, custom replacement overrides, empty/whitespace-only input, and leading/trailing separator trimming.

License

MIT — see LICENSE.