JavaScript is in constant evolution.
Since EcmaScript 2015, we got tons of new features and ways to work, and community is moving in the right way in order to provide a better developer experience.

Pipeline Operator is one of the most exciting proposal for the next JavaScript generation.
Currently in stage-0, it is only available using Babel as a transpiler or on Firefox enabling the flag --enable-pipeline-operator.

What is a Pipeline Operator?

Languages like OCaml, F#, Elixir, Elm, LiveScript, Hack (and many others) provides this amazing operator which transform this:

String.split(String.upcase("I love pipeline operator"))

# ["I", "LOVE", "PIPELINE", "OPERATOR"]

Into this:

"I love pipeline operator"
  |> String.upcase()
  |> String.split()

# ["I", "LOVE", "PIPELINE", "OPERATOR"]

So as you can see, it makes the task cleaner by creating a proper pipeline.
But how does it work in JavaScript?

Installation

First of all, the Pipeline operator is currently at stage-0, so you need to use Babel to transpile it.

$ yarn init -y
$ yarn add -D @babel/cli \
              @babel/core \
              @babel/preset-stage-1 \
              @babel/plugin-proposal-pipeline-operator

Next, you’ll need to create a .babelrc file and add the following code:

{
  "plugins": [
    ["@babel/plugin-proposal-pipeline-operator", { "proposal": "smart" }]
  ]
}

The last thing you’ll need to do, is adding the following snippet to your package.json file. Not a required step, but fits the purpose.

"scripts": {
  "start": "babel index.js --out-file output.js && node output.js"
}

Great! Now create a index.js file and you’re ready to go!

Using the Pipeline Operator

First of all, TC39 (Ecma Technical Committee) hasn’t specified yet which version of the Pipeline Operator will be included in the next generation of JavaScript.
You may have noticed that se set the proposal to smart while configuring the .babelrc file.
There are currently three proposals:

  • Smart

  • Minimal

  • F#

Each one of them provides different ways to handle EcmaScript features, we’ll use the smart proposal for now.

Let’s say we want to create a random number between 1 and 100.
That’s the standard way:

console.log(Math.floor(Math.random() * 100) + 1)

Ok great, one line! Wow! But this is too hard to read and to understand if you’re not a skilled developer, so… what about this?

Math.random()
  |> # * 100
  |> Math.floor
  |> # + 1
  |> console.log

That’s awesome! So let’s read it from top to bottom:

  1. Generate a random number

  2. Multiply the generated number (using the placeholder #) by 100

  3. Add one to the generated number (so it won’t return 0)

  4. Log it to the console

That is so clean!

The next scenario will make you fall in love with that amazing operator:

import { insertIntoDatabase } from "../database";

const user = {
  email:    "john@doe.com",
  password: "password"
}

function validateEmail(user) {
  return user.email.includes("@")
             ? user
             : new Error("Invalid email");
}

function validatePassword(user) {
  return user.password.length > 6
             ? user
             : new Error("Password is too short";)
}

user
  |> validateEmail
  |> validatePassword
  |> insertIntoDatabase

Ok, these are not real validation rules, but they make it clear how the Pipeline Operator works.

Imagine you have to build a REST API and you need to validate email and password, then insert them into a database.

First of all, you need to create two validation functions that will return the user itself if the validation rule is satisfied, otherwise they will throw an error.

So, now you got an user, you validate his email, his password and if everything is fine, you’ll save his data into a database!

But what if you want to use Promises?

import { insertIntoDatabase } from "../database";

const user = {
  email:    "john@doe.com",
  password: "password"
}

function validateEmail(user) {
  return new Promise((resolve, reject) => {
    return user.email.includes("@")
             ? resolve(user)
             : reject(new Error("Invalid email"));
  });
}

function validatePassword(user) {
  return new Promise((resolve, reject) => {
    return user.password.length > 6
              ? resolve(user)
              : reject(new Error("Password is too short"));
  });
}

(async () =>
  user
    |> await #
    |> validateEmail
    |> await #
    |> validatePassword
    |> insertIntoDatabase
)();

You can easily use async/await and you’re done!
Can you imagine how many things you can do with this amazing operator?

Did you like this article? Consider becoming a Patron!

This article is CC0 1.0 (Public Domain) licensed.