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 🙏

© 2025 – Pkg Stats / Ryan Hefner

canary-js

v3.3.1

Published

A minimalist, functional JavaScript toolkit for mere mortals. Curried, data-last, and easy to learn.

Downloads

310

Readme

CanaryJS

npm version License: MIT Minified size Types

A minimalist, functional JavaScript toolkit for mere mortals.


Why CanaryJS?

CanaryJS wraps the JavaScript you already know in a functional overcoat, then offers you a nice cup of tea.

  • Includes most built-in JS methods—but curried, data-last, and pleasantly unfussy.
  • Designed to be simple enough for mortals.
  • Easy to learn, hard to outgrow.
  • Works great on its own, or as an on-ramp to Ramda — and for deeper type-driven FP, Sanctuary.

If you’ve glanced at lodash/fp and felt it looked a bit like a supermarket sweep, CanaryJS is the corner shop: just the essentials, nicely arranged.


Installation

npm i canary-js

Zero dependencies. ES Module. Tree‑shakable.

Also available via CDN:

import * as C from 'https://esm.sh/canary-js@latest'

Quick Start

import * as C from 'canary-js'

const isEven = C.pipe(C.flip(C.modulo)(2), C.equals(0))
const add10 = C.add(10)

const transform = C.pipe(C.filter(isEven), C.map(add10))

const result = transform([1, 2, 3, 4])

console.log(result) // → [12, 14]

Core Ideas (in excessively tidy bullets)

| Principle | What it means | | -------------------------- | --------------------------------------------------------------------------------- | | Curried & data‑last | Functions take arguments one at a time, with data passed last—perfect for pipe. | | Pure & predictable | No mutation. Functions always return the same output for the same input. | | Partial application | You can pass fewer arguments to get a new function. Build behavior gradually. | | Built‑ins first | Array, String, Number, Object, and Boolean methods | | Ramda‑compatible names | Familiar vocabulary if you move to Ramda. | | Small surface | ~80 functions; your brain remains underwhelmed. |


What’s Inside?

Arrays

map, filter, reduce, find, findIndex, findLast, indexOf, lastIndexOf, some, every, includes, at, flat, flatMap, slice, concat, join, reverse, sort, length

Strings

split, trim, trimStart, trimEnd, repeat, toUpper, toLower, startsWith, endsWith, padStart, padEnd

Numbers

add, subtract, multiply, divide, modulo, abs, floor, round, ceil, pow

Objects

keys, values, entries, fromEntries, prop, freeze, seal, is

Comparison & Boolean

equals, not, negate, lt, lte, gt, gte

Core Utilities

identity, always, converge, tap, pipe, compose, curry, uncurry, addIndex, flip, binary, trinary

Control Flow

ifElse, cond, tryCatch

Discriminated Union Helpers

match

CanaryJS no longer ships its own ADT constructor. Instead, it recommends using Zod to define discriminated unions, then using match to pattern-match over them.

Note: There’s a naming collision here. Ramda also has a function named match, but theirs is for regular expression matching, while CanaryJS’s match is for pattern-matching over discriminated unions (sum types).
If you’re looking for regexes, reach for Ramda; if you’re looking for ADTs, CanaryJS and Zod have you covered.
Also note: Unlike most CanaryJS functions, match is not curried—you must call it as match(value, cases). You may also provide a fallback handler _ that will be used if no specific case matches.

Example:

import { z } from 'zod'
import { match } from 'canary-js'

const Shape = z.discriminatedUnion('kind', [
  z.object({ kind: z.literal('circle'), radius: z.number() }),
  z.object({ kind: z.literal('rectangle'), width: z.number(), height: z.number() }),
])

const shape1 = Shape.parse({ kind: 'circle', radius: 2 })
const shape2 = Shape.parse({ kind: 'rectangle', width: 3, height: 4 })

console.log(
  match(shape1, {
    circle: ({ radius }) => Math.PI * radius * radius,
    rectangle: ({ width, height }) => width * height,
  })
) // → 12.566370614359172

console.log(
  match(shape2, {
    circle: ({ radius }) => Math.PI * radius * radius,
    rectangle: ({ width, height }) => width * height,
  })
) // → 12

// With a fallback handler
console.log(
  match({ kind: 'triangle', base: 3, height: 4 }, {
    circle: ({ radius }) => Math.PI * radius * radius,
    rectangle: ({ width, height }) => width * height,
    _: shape => `Unknown shape: ${shape.kind}`,  // fallback
  })
) // → "Unknown shape: triangle"

CanaryJS integrates with Zod for pragmatic ADTs. If you prefer fully‑spec’d ADTs like Maybe or Either, see SanctuaryJS.


What’s not Inside (and where to find it)

| Feature | Where to look | | ---------------------------------------------------- | --------------- | | Placeholders (__) | Ramda | | Fancy combinators (juxt, lens, zipWith) | Ramda | | Maybe, Either, and other Fantasy‑Land‑certified ADTs | SanctuaryJS | | Lenses, traversals, profunctors (brace yourself) | Ramda & friends |

CanaryJS keeps the water shallow; when you’re ready to dive, Ramda and Sanctuary have the deep end nicely chlorinated.


Naming Aside

Why CanaryJS?

It’s named after Canary Wharf in London, where the idea for the library clicked into place—over a coffee and a long think about functional programming.

This is a second attempt, after learning firsthand how quickly a utility library can grow too large, while still not quite measuring up to its inspirations. CanaryJS is a fresh start—intentionally small, focused, and designed to help others avoid some of the detours I took along the way.

Nothing to do with canaries in mines, alerts, or early warning systems. Probably.


License

MIT © 2025 Brad Mehder

canary-js