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

matches

v0.5.1

Published

Powerful pattern matching for Javascript

Downloads

1,297

Readme

matches.js

Matches.js brings the power and expressiveness of pattern matching to Javascript.

Usage

Matches.js exports one function, pattern.

var pattern = require("matches").pattern;

pattern(patternObj)

The simplest way is to give it an object with the keys being patterns, and the values being functions. Each pattern will be tried in order until a match is found.

var arrayElems = pattern({
  '[]': function () { 
    return "This array is empty."; 
  },
  '[x]': function (x) { 
    return "This array has one element: " + x; 
  },
  '[x, y]': function (x, y) { 
    return "This array has two elements: " + x + " and " + y;
  },
  '[x, y, ...]': function (x, y) {
    return "This array is long. The first two elements are: " + x + " and " + y;
  }
});

arrayElems([1, 2, 3]);

pattern(patternStr, successFn)

You can create individual pattern and function pairs.

var emptyArray = pattern('[]', function () { return "Empty array" });

// "Empty array"
emptyArray([]);

// TypeError: "All patterns exhausted"
emptyArray(12);

pattern(patternFn, successFn)

You can also create your own custom pattern functions. The patternFn takes an array of arguments, and should return false for no match, or a new array of arguments to forward on to the successFn.

var greater42 = function (args) {
  if (args[0] >= 42) return [args[0]];
  return false;
};

var customPattern = pattern(greater42, function (x) {
  console.log(x);
});

// Logs 54
customPattern(54);

// TypeError: "All patterns exhausted"
customPattern(12);

Combinators

You can combine any of these methods to create unique match chains using the alt combinator.


var wildcard = pattern('_', function () { return "No matches."; });
var mychain = pattern('1', function () { return "One"; })
  .alt({
    '2': function () { return "Two"; },
    '3': function () { return "Three"; }
  })
  .alt(wildcard);

// 'One'
mychain(1);

// 'Two'
mychain(2);

// 'No matches.'
mychain(5);

Multiple Arguments

Separate matches for multiple arguments with a comma. Since you can pass any number of arguments to functions in Javascript, Matches.js is not strict and will happily combine patterns for varying numbers of arguments.

var myfn = pattern({
  // Matches on the first three arguments. If more are passed, they are ignored.
  '1, "foo", [a, ...]': function (a) { return a; },

  // Matches on the first two arguments, ignoring the rest
  'a, fn@Function': function (a, fn) { return fn(a); },

  // Matches anything
  '_': function () { return null; }
});

// 12
myfn(6, function (x) { return x * 2; }, "foo", "bar");

// null
myfn(1, 2, 3, 4);

Performance

Pattern strings are compiled to pure Javascript functions and then cached. So beyond initial creation for the first instance of a pattern string, there is very little overhead. Unless you programmatically create dynamic patterns, you should only see a slight hit at the start of your application as the patterns are compiled. Benchmarks coming soon.

Patterns

Literals

Check for specific values using number or string literals, null, or undefined.

var myfn = pattern({
  // Null
  'null' : function () {...},

  // Undefined
  'undefined' : function () {...},

  // Numbers
  '42'    : function () { ... },
  '12.6'  : function () { ... },
  '1e+42' : function () { ... },

  // Strings
  '"foo"' : function () { ... },

  // Escape sequences must be double escaped.
  '"This string \\n matches \\n newlines."' : function () { ... }
});

Wildcards

Underscores will match successfully on any value but ignore it. A single underscore works well as a catch all pattern.

var myfn = pattern({
  // Match if second argument is 12, ignoring the first
  '_, 12' : function () { ... },

  // Match on anything
  '_' : function () { ... }
});

Identifiers

Patterns that start with lowercase letters will pass the value to the function. Values are passed to the function in the same right to left order they are declared in the pattern.

var myfn = pattern({
  // Pass on the second argument if the first is 12
  '12, x': function (x) { ... },

  // Pass on the first and third argument, ignoring the second
  'x, _, y': function (x, y) { ... }
});

Arrays

Match on the entire array, or only a few values.

var myfn = pattern({
  // Empty array
  '[]' : function () { ... },

  // Strict comparison on contents
  '[1, 2, 3]': function () { ... },

  // Grab the first value, ignoring the rest
  '[x, ...]': function (x) { ... },

  // Split it into a head and tail
  '[head, tail...]': function (head, tail) { ... },

  // Grab the first and last items, ignoring the middle
  '[x, ..., y]': function (x, y) { ... },

  // Grab the last item
  '[..., last]': function (last) { ... },

  // Make a shallow clone
  '[clone...]': function (clone) { ... },

  // Grab the first item, but also pass on the whole array
  'arr@[first, ...]': function (arr, first) { ... }
});

Objects

Matches.js currently supports strict object comparison, meaning it will match if the object contains the specified keys and no others.

var myfn = pattern({
  // Empty object
  '{}': function () { ... },

  // Check that an object has only two keys 'x' and 'y', and pass to the function
  '{x, y}': function (x, y) { ... },

  // Check that an object has a key that contains an array
  '{children: [a, b, ...], other: _}': function (a, b) { ... }
})

Core Javascript Types

Typecheck arguments using Number, String, Date, RegExp, Function, Array, or Object.

var myfn = pattern({
  // Takes a function and an array
  'fn@Function, arr@Array': function (fn, arr) { ... },

  // Takes a function and an object
  'fn@Function, obj@Object': function (fn, obj) { ... }
});

Adt.js Types

Matches.js has builtin support for adt.js types. Adt.js is a library for building algebraic data types in Javascript.

// Create a new adt.js type
var Tree = adt.data({
  Empty : adt.single(),
  Node  : adt.record("val", "left", "right")
});

var mytree = Tree.Node(12, Tree.Empty(), Tree.Node(42, Tree.Empty(), Tree.Empty()));

var myfn = pattern({
  // Match on an Empty tree node
  'Empty': function () { ... },

  // Match on a Node with a value of 12
  'Node(12, _, _)': function () { ... },

  // Match on a Node that has non-Empty children
  'Node(_, Node, Node)': function () { ... }

  // Match on a Node that has a left child Node of 42 and an Empty right node
  'Node(val, Node(42, _, _), Empty)': function (val) { ... }
});

Find out more about adt.js: https://github.com/natefaubion/adt.js