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

transplexer

v1.1.0

Published

Simple and lightweight reactive programming

Readme

Build Status

Transplexer

A library for trivial reactive programming.

Contents

Overview

The name transplex was derived from the prefix 'trans-' and suffix '-plex'. Togther they mean 'consisting of something across'. This gist of this library is that it provides means for bringing together the source of change and the code that wants to react to it. A fancy name for this pattern is the observer pattern.

The transplexer library provides a simple, uniform way of creating pipelines for propagating changes, this allowing us to specify ahead of time, how various changes affect our application. This is in contrast with imperative programming style in which the handling of each change is determined on the spot. Transplexer achieves this goal with very little code by providing powerful tools that can be adapted to various scenarios.

Transplexer and functional reactive programming

Transplexer can do many of the things that can be done with the more common functional reactive libraries like RxJS, Bacon.js, zen-observables or Xstream. Although it does so in a completely different style, transplexer is able to achieve designs that are quite similar in spirit. Some of the difference between the transplexer and functional reactive libraries are:

  • It isn't focused on functional programming, as it's a lower-level library.
  • It does not wrap the function that produces events/values, instead acting as an object that can accept values and transmit them.
  • It can only do push as data flow is one-way.
  • It does not provide an opportunity to hook into the subscription process or change behavior per subscriber.
  • It keeps the door open for extension rather than trying to become a complete utility belt (although a seprate package provides tools that you can use, if that's what you want).

Installation

Install from the NPM repository with NPM:

npm install transplexer

or with Yarn:

yarn add transplexer

Quck tour

We use transplexer by imporing its one and only function:

import pipe from 'transplexer';

let p = pipe();

The pipe can be subscribed to, in order to receive changes:

function showText(text) {
  console.log(text);
}

p.connect(showText);

Now the showText() function will be called whenever something is sent down the pipe. To send things down the pipe, we call the send() function:

p.send('Hello, World!');
// `showText()` logs 'Hello, World!'

The send() function takes any number of arguments, and they are all relayed to the connected callbacks.

p.send('Hello', ',', 'World', '!');
// `showText()` logs 'Hello' ',' 'World' '!'

The main power of the pipes comes from the transformers. In order to keep transformers as flexible as possible, we chose to implement them as function decorators (not to be confused with ES6 decorators).

Here is an example with a few transformers.

function joinTransformer(next) {
  return function (...parts) {
    next(parts.join(' '));
  };
}

function lowerCaseTransformer(next) {
  return function (str) {
    next(str.toLowerCase());
  };
}

let q = pipe(joinTransformer, lowerCaseTransformer);
q.connect(showText);

The order in which transformers are applied is the same as the order in which they are specified. Transformers exercise complete control over what they can do with the value and whether to relay it to the callback or not. To give you a taste of what kind of interesting designs you can achieve with transformers, here's a short, inconclusive, list of things transformers can do:

  • Change the input values before relaying.
  • Relay the input values as is.
  • Skip invoking the next transformer.
  • Invoke the next transformers multiple times.
  • Schedule the invocation of the next transformer (e.g., requestAnimationFrame(), setTimeout(), etc.).
  • Perform asynchronous tasks before invoking the next transformer (e.g., perform an XHR request and then invoking the next transformer with the result).
  • And more... you get the idea.

Pipes can be connected to each other. Since connect() function takes an arbitrary function, it can also take another pipes's send() function.

let p1 = pipe();
let p2 = pipe();

p1.connect(p2.send);

p2.connect(console.log);

p1.send('Hello, pipe!');
// logs 'Hello, pipe!'

By connecting multiple pipes to a single pipe, we effectively branch the source pipe. It is also possible to connect multiple pipes to a single pipe:

let p1 = pipe();
let p2 = pipe();
let p3 = pipe();

p1.connect(p3.send);
p2.connect(p3.send);

p3.connect(console.log);

p1.send('Hello, pipe!');
// logs 'Hello, pipe!'

p2.send('Hello, other pipe!')
// logs 'Hello, other pipe!'

With this, we have everything we need to build the pipelines for our applications. This quick tour covered the basics of using the pipes. The next section will provide a more formal documentation for hte pipes API as well as features not covered in the tour.

API documenation

Pipe creation

An empty pipe is created by calling the pipe() function without any arguments.

pipe();

One or more transformers can be specified that control the passing of the values through the pipe.

pipe(t1, t2);

Transformers

Transformers are function decorators that control the passing of the values through the pipe.

Transformers take a callback function as their argument and are expected to return a function that takes one or more values, and potentially invokes the callback with a poentially modified value.

Decorators take the following general form:

function decorator(next) {
  return function wrapper(...args) {
    next(...args);
  };
}

The outer function is the decorator. It takes the next callback, and returns a function that replaces the callback with a function that may or may not behave differently and may or may not call the callback. The return value of the wrapper function is ignored.

Here's an example of a transformer that increments numbers by 1:

function inc(next) {
  return function (n) {
    next(n + 1);
  };
}

pipe(inc);

Transformers should not make any assumptions about the callback except for the following:

  • The callback can take any number of arguments.
  • The callback does not have a meaningful return value.

As a convention, we name the callback next so that it's easier to tell that it's a transformer.

Pipe instance methods

connect(observer)

Connect an observer to the pipe.

Observers are arbitrary functions that are invoked any time a value is sent down the pipe. Since any number of values can be passed down the pipe at once, observers can take any number of arguments matching the values that were sent.

function myObserver(x, y) {
  console.log(x, y);
}

let p = pipe();
p.connect(myObserver);

This method returns a function that removes the observer to the pipe (disconnects it).

let p = pipe();
let disconnect = p.connect(myObserver);
disconnect();

send(...values)

Send zero or more values through a pipe.

Values are send through the pipe over to the observers using the send() method. This method takes an arbitrary number of arguments which are then passed through any transformers, and finally to the observers.

let p = pipe();
p.send(1, 'text');
p.send(1);

There is no limit to how many values at once and how many times we can send down a pipe.

extend(...transformers)

Create a new pipe that is connected to this one.

Pipes can be 'extended' using the extend() method. This method takes any number of transformer functions. It creates a new pipe with the specified transformers, connects it to the pipe on which extend() is called, and returns the new pipe.

let p1 = p.extend(t1, t2)

This is a shortcut for doing:

let p1 = pipe(t1, t2);
p.connect(p1.send);

push(...transformers)

Add one or more transformers to the end of the pipe.

For example:

let p = pipe(t1, t2);
p.push(t3, t4);  // t1, t2, t3, t4

pop(index = null)

Remove a transformer form the end of the pipe or at specified index.

To remove the elements from the end, we use pop() without any arguments.

let p = pipe(t1, t2);
p.pop();  // t1

The pop() method can be used with a single numeric index to remove a specific item in the pipe:

let p = pipe(t1, t2);
p.pop(0);  // t2

unshift(...transformers)

Add one or more transformers to the beginning of the pipe.

For example:

let p = pipe(t1, t2);
p.unshift(t3);  // t3, t1, t2

When multiple transformers are added at once, they retain the order in which they are specified as unshift() arguments:

let p = pipe(t1, t2);
p.unshift(t3, t4);  // t3, t4, t1, t2

shift()

Remove a transformer from the beginning of the pipe.

This is a shortcut for pop(0) is shift().

let p = pipe(t1, t2);
p.shift();  // t2

remove(transformer)

Remove all copies of the transformer from the pipe.

To remove a specific transformer to which we hold a reference, we can use the remove() method. This method takes a single transformer function as its argument and removes it from the pipe.

let p = pipe(t1, t2);
p.remove(t1);  // t2

This method will remove all copies of the transformer. If we have multiple copies of the same transformers, all of them are removed:

let p = pipe(t1, t2, t1);
p.remove(t1);  // t2