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

ruply

v1.0.1

Published

run[If] and apply functions for easy-to-read code

Readme

ruply · License (X11/MIT) npm version Build Status Coverage status

run[If] and apply are functions that can help you craft easy-to-read code.

run

run forwards the first argument to the callback, and returns the result.

// Calculate the area.
const area = run(
	getSize(),
	({ width, height }) => width * height
);

width and height are neatly confined to the callback. The alternative without run has those variables overstay their welcome, polluting the scope:

// Calculate the area.
const { width, height } = getSize();
const area = width * height;

apply

apply forwards the first argument to the callback ‒ just like run does ‒ but returns that argument instead of the result.

// Remove the item from the selection.
setState(previousSelection => apply(
	new Set(previousSelection),
	selection => selection.delete(item)
));

The alternative without apply is more wordy:

// Remove the item from the selection.
setState(previousSelection => {
	const selection = new Set(previousSelection);
	selection.delete(item);
	return selection;
});

runIf

runIf skips the callback if the first argument is nullish, and behaves the same as run otherwise. runIf is to run as the ?. operator is to the . operator.

// Parse the timestamp (if any).
const timestamp = runIf(
	response.data.timestamp,
	Date.parse
);

Alternatives include this:

// Parse the timestamp (if any).
let { timestamp } = response.data;
if (timestamp != undefined) {
	timestamp = Date.parse(timestamp);
}

And this*:

// Parse the timestamp (if any).
let timestamp = Date.parse(response.data.timestamp);
if (isNaN(timestamp)) {
	timestamp = undefined;
}

And this dangerous** one:

// Parse the timestamp (if any).
const timestamp = response.data.timestamp
	&& Date.parse(response.data.timestamp);

[*] In the alternative with isNaN, invalid timestamps (such as 'invalid') are indistinguishable from missing timestamps. This is likely unexpected behaviour.

[**] In the alternative with the && operator, Date.parse is skipped not only if the timestamp is undefined but also if it is '' (or any other falsy value). This too is likely unexpected.

runIf and ??

You can combine runIf and the ?? operator to provide a fallback used if the callback is skipped.

return runIf(event.data, JSON.parse) ?? {};

Installation

Install ruply using npm or Yarn and import the functions:

import { run, apply, runIf } from 'ruply';

Under the hood

These are simplified implementations of run[If] and apply (without support for promises or chains):

function run(value, callback) {
	return callback(value);
}

function apply(value, callback) {
	callback(value);
	return value;
}

function runIf(value, callback) {
	return value != null ? callback(value) : value;
}

Rationale

These functions are designed to help your code better convey your intentions to the reader.

Non-goals include:

  1. producing the shortest possible code, and
  2. producing clever code.

Use run[If] and apply in situations where you feel they help the reader of your code.

More examples

Shielded variable

let available = 0;
function generateID() {
	return available++;
}

run scopes the variable, protecting it from accidental access.

const generateID = run(0, available => () => available++);

Encapsulated logic

logger.log(`Received ${bundles.reduce(
	(sum, { messages }) => sum + messages.length, 0
)} message(s)`);

run moves the summing logic outside the template literal.

run(
	bundles.reduce(
		(sum, { messages }) => sum + messages.length, 0
	),
	messageCount =>
		logger.log(`Received ${messageCount} message(s)`)
);

Side effect in fallback

if (data.has(index)) {
	return data.get(index);
}
// If the buffer does not exist, allocate it…
const buffer = Buffer.alloc(size);
// …and store it in the map.
data.set(index, buffer);
return buffer;

apply rearranges the pieces, producing code closer to human speech.

return data.get(index)
	?? apply(
		// If the buffer does not exist, allocate it…
		Buffer.alloc(size),
		// …and store it in the map.
		buffer => data.set(index, buffer)
	);

Timed asynchronous function

const start = performance.now();
const result = await queryDatabase();
console.log(`${performance.now() - start} ms`);
return result;

apply removes the need for the short-lived variable, and places return and queryDatabase() closer together.

const start = performance.now();
return apply(
	queryDatabase(),
	() => console.log(`${performance.now() - start} ms`)
);

The await keyword is optional, as apply is promise-aware.

Optional chain

const token =
	request.headers.authorization != undefined
		? /^Bearer\s+(.*)$/.exec(
			request.headers.authorization
		)?.[1]
		: undefined;

runIf cuts out the undefined check (for cases where the header is missing) as well as the ?. operator (for cases where the regular expression does not match).

const token = runIf(
	request.headers.authorization,
	headerValue => /^Bearer\s+(.*)$/.exec(headerValue),
	([, token]) => token
);

If you prefer keeping the ?. operator, then you should.

const token = runIf(
	request.headers.authorization,
	headerValue => /^Bearer\s+(.*)$/.exec(headerValue)
)?.[1];

Optional step

const value = await cache.get(key);
// Disregard the value if it has expired.
if (value == null || value.expiration < Date.now()) {
	return null;
}
return value;

runIf cuts out the null check.

return runIf(
	cache.get(key),
	// Disregard the value if it has expired.
	value => value.expiration < Date.now() ? null : value
);

The await keyword is optional, as runIf is promise-aware.

Memoisation

const orders = new Map();
function memoGetOrder(id) {
	if (orders.has(id)) {
		return orders.get(id);
	}
	const order = getOrder(id);
	orders.set(id, order);
	return order;
}

run scopes the map, while apply rearranges the pieces of the function body to match the human speech equivalent.

const memoGetOrder = run(new Map(), orders =>
	id => orders.get(id)
		?? apply(getOrder(id), order => orders.set(id, order))
);

Pronunciation

/ɹʌˈplaɪ/

Like run apply.

License (X11/MIT)

Copyright (c) 2020, 2021 Pimm "de Chinchilla" Hogeling

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. in no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the Software or the use or other dealings in the Software.