npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details


  • User packages



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.


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 🙏

© 2023 – Pkg Stats / Ryan Hefner




Functional match expressions for JS





The missing match expression for JavaScript. Use functional pattern matching constructs familiar from languages like Rust to sidestep the limitations of switch statements, reduce messy ternary expressions and if/else chains, and assign variables based on arbitrarily complex conditions.

NPM npm bundle size

GitHub stars GitHub forks GitHub watchers Follow on GitHub


yarn add patturn


npm install --save patturn

Match expressions

The match() function behaves like a superpowered switch statement that returns a value from the matched branch. It accepts a value to match against, an array of matchers, and an optional default return value.

import { match } from "patturn";
const ANSWER = 42;

const result = match(
    [0, "zilch"],
    [3, "the magic number"],
    [42, "the meaning of life"],
    [420, "nothing to see here, officer"],
  "no match"
// result: "the meaning of life"

The return types may be heterogeneous, and when using TypeScript can be inferred, or constrained as needed.

Guards and Returns

Each matcher consists of a guard and a return. Guards check if a value matches a condition, and returns specify the value to return from the match. Each can be a value, expression, array of values, function called with the value, or any combination thereof:

import { match } from "patturn";
const name = "benedict";

match(name, [
  ["thomas", "t-bone"],
  [(n) => n.includes("ben"), `${name} cumberbatch?`],
  [(n) => n.length > 8, (_n) => "too long, don't care"],
]); // returns "benedict cumberbatch?"

Note: guards use strict equality, or the boolean return value if a function.

Guard Lists

To match multiple values in a single match branch, simply pass in an array of values as the guard. This is the equivalent of the fallthrough behavior in switch, and any matching value will immediately break with the associated return:

import { match } from "patturn";
const flavor = "strawberry";

const preference = match(
    [["chocolate", "vanilla"], "obviously good"],
    [["mint chip", "strawberry"], "kinda okay"], // matches second guard case
    ["pistachio", "lowkey favorite"],
    ["rocky road", "too much going on"],
  "no opinion"
// preference: "kinda okay"

Order matters

Ordering of matchers is important -- the first guard to pass is the one used. In the example below, both the third and fourth guards would pass, but the fourth is never run:

import { match } from "patturn";

type User = { name: string; id: number };
const me: User = { name: "rekt", id: 32 };

match<User, boolean | null>(me, [
  [(u) => === 1, true],
  [(u) => === "he-who-must-not-be-named", null],
  [(u) => < 1000, true],
  [(u) => === "rekt", false],
]); // returns `true`

Match Signature

function match<In, Out = In>(input: In, matchers: Array<MatchBranch<In, Out>>, defaultValue?: Out): Out | undefined;

type MatchBranch<In, Out> = [Guard<In>, Return<In, Out>];
type Guard<In> = In | In[] | ((input: In) => boolean);
type Return<In, Out> = Out | ((input: In) => Out);

When statements

The when() function behaves much like match(), but doesn't return a value. It has the added option of running lazily, stopping after the first match, or greedily and running through every match. It's also a lot like a switch, useful for running side-effects based on complex conditions.

import { when } from "patturn";
const album = { artist: "Radiohead", title: "OK Computer", year: 1997 };

      (a) => a.year >= 1990 && a.year <= 2000,
      (_) => console.log("playing 90's music..."),
    [(a) => a.artist === "Sisqo", () => process.exit(1)],
    [(a) => a.artist === "Radiohead", () => setVolume(100)],
// - logs "playing 90's music..."
// - blasts volume

When Signature

function when<In>(input: In, matchers: Array<WhenBranch<In>>, lazy?: boolean): void;

type WhenBranch<In> = [Guard<In>, (input: In) => void];
type Guard<In> = In | In[] | ((input: In) => boolean);


MIT © Tobias Fried