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

lollang

v0.1.0

Published

A laughter-keyword language that transpiles to JavaScript. Every keyword is a laugh.

Readme

lollang

A laughter-keyword language that transpiles to JavaScript. Every keyword is a laugh.

CI npm license: MIT

haha factorial(n) {
    lmfao (n <= 1) { rofl 1; }
    rofl n * factorial(n - 1);
}

xd(factorial(6));   // 720

What is it

LOLLang is a tiny language whose every keyword is a variant of laughter (haha, lol, rofl, kek, lmao, …). It transpiles to JavaScript via a direct token-substitution and is otherwise a strict subset of JS — the operators, identifier rules, and expression grammar are all unchanged.

Two things make this package interesting:

  • unlulzcate — translates .lol source to JavaScript. A single regex pass that preserves strings, template literals, and comments verbatim.
  • oblulzcate — the inverse: JavaScript → LOL. AST-aware (via Acorn) so that else if, console.log(…), and undefined references are handled correctly — things a naïve regex cannot do.

The full language spec is at docs/SPEC.md.

Install

npm install lollang
# or globally for the CLI
npm install -g lollang

Requires Node ≥ 18.

CLI

lollang unlulzcate hello.lol -o hello.js     # LOL → JS
lollang oblulzcate hello.js  -o hello.lol    # JS  → LOL
lollang run        hello.lol                 # transpile + execute
lollang repl                                 # interactive lol> prompt

Stdin and stdout are first-class: pipe in, pipe out.

echo 'xd("hi");' | lollang unlulzcate
# → console.log("hi");

cat src/index.js | lollang oblulzcate > src/index.lol

Aliases: transpileunlulzcate, obfuscateoblulzcate.

API

import { unlulzcate, oblulzcate, run, startRepl } from "lollang";

unlulzcate('xd("hi");');                      // 'console.log("hi");'
oblulzcate('console.log("hi");');             // 'xd("hi");'
await run("lol x = 41; x + 1;");              // 42
await startRepl();                            // interactive

oblulzcate accepts options for the asymmetric edges:

oblulzcate(source, {
  translateConsoleLog: false,   // keep console.log literal
  translateUndefined:  false,   // keep undefined literal
});

Keyword map

| LOL | JS | | LOL | JS | | ----------- | ------------- | --- | ---------- | ---------- | | lol | let | | lulz | break | | lmao | const | | jaja | continue | | haha | function | | bahaha | true | | rofl | return | | mwahaha | false | | lmfao | if | | teehee | null | | hehe | else if | | imded | undefined| | kek | else | | ahaha | class | | hihi | while | | omegalul | new | | heh | for | | me | this | | lolwut | try | | kekw | switch | | lolnope | catch | | pepega | case | | ded | throw | | lulw | default | | xd | console.log | | yoink | import | | yeet | export | | giggle | async | | waitforit | await | | | |

Identifiers that collide with keywords can be escaped with a $ prefix: $haha becomes the JS identifier haha.

How it works

unlulzcate (LOL → JS)

A single regex pass. The trick is the alternation order: string literals, template literals, line comments, and block comments are matched first, then the engine falls through to identifier-shaped tokens, then any remaining single character. Only identifier tokens are looked up in the keyword map, so lol x = "haha"; cannot accidentally rewrite the word inside the string.

"…" | '…' | `…` | // …  | /* … */  | $IDENT | \bIDENT\b | .
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   ^^^^^^^   ^^^^^^^^^   ^
preserved verbatim                   escape    candidate   fallback

oblulzcate (JS → LOL)

The inverse needs an AST because three rewrites are not local:

| Rewrite | Why an AST | | ----------------------------------- | ---------------------------------------------------- | | else ifhehe | Two JS tokens with arbitrary whitespace between. | | console.log(…)xd(…) | Must rewrite the callee of a call, not every match.| | undefinedimded | Only value-position references; never property keys, member access, or binding names. |

Implementation: Acorn tokenizes the source for keyword-position edits, the parser produces an AST for the three special cases, and edits are applied right-to-left so offsets stay valid.

Limitations

  • Reserved identifiers. You can't name a binding after a laugh keyword in LOL source unless you escape it with $ (e.g. $haha).
  • console.log only. The reverse direction rewrites only the call form of console.log. Standalone references (const f = console.log;) stay literal — by design, because rewriting them as xd would change behavior if console.log were later reassigned.
  • No source maps. v1 emits no source maps; line numbers may shift due to length-changing substitutions like xdconsole.log.
  • No type system. Add :type annotations and strip them yourself if you want TypeScript-shaped hints.

Development

npm install
npm run build       # tsup → dist/ (esm + cjs + .d.ts)
npm test            # vitest
npm run check       # lint + typecheck + test
npm run dev         # tsup --watch

Tests cover every spec example plus round-trip JS → LOL → JS for a corpus of common shapes (classes, async, modules, switch, control flow).

License

MIT © 2026 aj