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 🙏

© 2024 – Pkg Stats / Ryan Hefner

pattycake

v0.0.2

Published

Zero-runtime pattern matching

Downloads

1,706

Readme

⚠️ Note: this is highly experimental software. Here be dragons 🐉

🎂 pattycake

Zero-runtime pattern matching. (~10-12x faster 🔥)

Pattycake is an optimizing compiler for ts-pattern that lets you have your cake (expressive pattern matching), and eat it too (zero runtime overhead).

Install

npm install pattycake
// next.config.js
const pattycake = require('pattycake');

module.exports = pattycake.next({
  // your next.js config
});
// vite.config.js
import { defineConfig } from 'vite';
import pattycake from 'pattycake';

export default defineConfig({
  plugins: [pattycake.vite()],
});
const pattycake = require('pattycake');

module.exports = {
  webpack: {
    plugins: { add: [pattycake.webpack()] },
  },
};
const pattycake = require('pattycake');

module.exports = {
  plugins: [pattycake.webpack()],
};

About

ts-pattern is a great library that brings the ergonomics of pattern matching from languages like Rust and OCaml to Typescript, but at the cost of being orders of magnitude slower.

pattycake compiles ts-pattern's match() expressions into an optimized chain of if statements to completely eliminate that cost. In our initial benchmarks, it outperforms ts-pattern by usually ~36-66x.

In essence, pattycake converts a ts-pattern match() expression like this:

let html = match(result)
  .with(
    { type: 'error', error: { foo: [1, 2] }, nice: '' },
    () => '<p>Oups! An error occured</p>',
  )
  .with({ type: 'ok', data: { type: 'text' } }, function (data) {
    return '<p>420</p>';
  })
  .with(
    { type: 'ok', data: { type: 'img', src: 'hi' } },
    (src) => `<img src=${src} />`,
  )
  .otherwise(() => 'idk bro');

Into this:

let html;
out: {
  if (
    result.type === 'error' &&
    Array.isArray(result.error.foo) &&
    result.error.foo.length >= 2 &&
    result.error.foo[0] === 1 &&
    result.error.foo[1] === 2
  ) {
    html = '<p>Oups! An error occured</p>';
    break out;
  }
  if (result.type === 'ok' && result.data.type === 'text') {
    let data = result;
    html = '<p>420</p>';
    break out;
  }
  if (
    result.type === 'ok' &&
    result.data.type === 'img' &&
    result.data.src === 'hi'
  ) {
    let src = result;
    html = `<img src=${src} />`;
    break out;
  }
  html = 'idk bro';
  break out;
}

Feature parity with ts-pattern

Notes

Fallback / compatibility with ts-pattern

If pattycake is unable to optimize a match() expression, it will fallback to using ts-pattern. This is enabled right now because we don't support the full feature set of ts-pattern.

Inlining handlers

One performance problem of ts-pattern's are handler functions:

match(foo)
  .with({ foo: 'bar', () => /* this is a handler function */)
  .with({ foo: 'baz', () => /* another one */)

Function calls usually have an overhead, and a lot of the time these handlers are small little functions (e.g. (result) => result + 1) which can be much faster if just directly inlined in the code.

Additionally, a match() with many branches means creating a lot of function objects in the runtime.

The JIT-compiler and optimizer in JS engines can do inlining of functions, but in general with JIT you need to run your code several times or it to determine what to optimize.

So when possible, pattycake will try to inline function expression (anonymous functions / arrow functions) handlers directly into the code if it is small.

IIFEs

When possible, pattycake will try to generate a block of code (like in the example above). But there are times where this is not possible without breaking the semantics of source code.

Roadmap

Right now, the goal is to support the full feature set of ts-pattern, or at least a sufficient amount. After, the ideal is that we compile pattern matching expressions into code that would be faster than what you would write by hand.