RegExp syntax for Observables: Never Been Easier!
Tags: rxjs, angular, webdev, javascript
Published: 2019-12-23 16:00:00

Imagine we need to implement a drag-n-drop behavior.

For that, we have three event streams: `mousemove$`, `mousedown$`, `mouseup$`. So we want to capture `mousemove$` events after `mousedown$` emitted and before `mouseup$`.

Let's draw a marble diagram of the event streams we have:

```js
mousedown$  --o------------
mousemove$  -o-o-o-o-o-o-o-
mouseup$    ------------o--
```

<figcaption>Every event stream is represented with separate line.<br/><code>o</code> stands for event on the stream. <code>-</code> is a separator to represent passing time</figcaption>

For better readability let's substitute all the `o`s to respective letters of the streams:

```js
mousedown$  --d------------
mousemove$  -m-m-m-m-m-m-m-
mouseup$    ------------u--
```

<figcaption>'d' will now stand for mouse-down event, 'm' for mouse-move, 'u' for mouse-up</figcaption>

Now that we have distinct event names, we can simplify our diagram to a single line of events:

```js
events$     -mdm-m-m-m-mum-
```

Let's remove the time `-` signs as well, we don't them:

```js
events$      mdmmmmmum
```

Okay, to rephrase our task in terms of the new diagram: we need to capture the `m` events between `d` and `u` emissions.

## 🤔

Hmm...

> "we need `m`s between `d` and `u`"...

Sounds familiar...

Ah! If that was a string, we could easily do it with a regular expression:

```js
/dm*u/.exec('mdmmmum')
```

Would give us the needed `dmmmu` without trailing mouse-move `m` events...

Right?

If only we had a library to select events from streams with regexes...

## 🤩 Introducing Regular Expressions for Rx

With [`exprs-rx`](https://github.com/expressions-for-reactive-streams/js-rx-exprs) package you can now query your streams with regular expressions like syntax!

```js
mousedown$  --d------------
mousemove$  -m-m-m-m-m-m-m-
mouseup$    ------------u--

                 dm*u

result$     --dm-m-m-m-mu|
```

**Benefits:**

- clear and extensible syntax
- no need to remember dozens of operators
- no need to import them, which reduces bundle size
- with more implementations to come — one syntax for all stream libraries (`monetjs`, `kefirjs`, `baconjs`, `TC39 Observables`, etc)

## Example

Here's our drag-n-drop example in JS:

```js
import { exec } from 'exprs-rx';

const item = document.getElementById('item');

const D = fromEvent(item, 'mousedown');
const M = fromEvent(document, 'mousemove');
const U = fromEvent(document, 'mouseup');

exec(
  'DM*U'         // <- regular expression
  , { D, M, U }  // <- streams that will be used
)
  .pipe(
    // ... apply any operators ...
  )
  .subscribe(console.log);
```

> Repo [//github.com/expressions-for-reactive-streams/js-rx-exprs](https://github.com/expressions-for-reactive-streams/js-rx-exprs)

Currently, the library supports capital letters `A-Z` that represent a single emission of a corresponding stream.

And a repeat `A*` notation that will consume multiple events from the corresponding stream, until completion or until next entry in the regex matches.

And much more to come: `()`, `[]`, `!`, etc!

For regex specification and plans on vocabulary, please, see this repo [github.com/expressions-for-reactive-streams/spec-regular-expressions](https://github.com/expressions-for-reactive-streams/spec-regular-expressions)

## Try it

{% stackblitz rxjs-regular-expressions embed=1&file=index.ts&hideExplorer=1 %}

##  Install it

```
npm i exprs-rx
```

## 🙌 Outro

The idea is to [extend the expressions syntax](https://github.com/expressions-for-reactive-streams/spec-regular-expressions) to cover 80% of routine RxJS tasks. And maybe add [combination commands](https://github.com/expressions-for-reactive-streams/spec-combine-expressions). The possibilities are endless!

For upcoming amazing updates — follow me here and on [twitter](https://twitter.com/kddsky)

If you've found this post worth sharing — please, use this tweet:

{% twitter 1209142587900256256 %}

## 🙂 Thanks!