Introducing fancy-regex - JS/TS regexes with whitespace, comments, and interpolation!
Tags: javascript, typescript, showdev
Published: 2021-01-27 23:35:15

Regexes in JavaScript are a fantastic tool for matching text, manipulating strings, performing validations, and a myriad of other tasks (just [don’t try to use them to parse HTML](https://stackoverflow.com/a/1732454)!) Thanks to ever-improving Unicode support with [the `u` flag](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/unicode) and [Unicode property escapes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes), regexes in Javascript have never been more powerful.

However, one area where JavaScript regexes have consistently fallen behind is developer experience. [In Ruby](https://ruby-doc.org/core-3.0.0/Regexp.html#class-Regexp-label-Options), interpolation of variables into regexes is supported by default, and support for multiline whitespace indentation and comments can easily be enabled with the `x` flag. In JavaScript, meanwhile, you end up clumsily joining strings together using the `RegExp` constructor, using lots of double-escaped backslashes. Without comments or proper indentation, it’s no wonder that people say regexes are a [write-only language](https://en.wikipedia.org/wiki/Write-only_language).

That’s why I built [`fancy-regex`](https://www.npmjs.com/package/fancy-regex)! This tiny npm package uses the power of [tagged template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates) to provide a developer experience very similar to Ruby’s `/#{regex}/x`.

Let’s take a quick look at a couple of examples:

```ts
const myFancyRegex = regex`.{${4 + 1}}`
```

Simple enough. If you don’t need to use any flags, the `regex` function is directly callable on template strings.

If you _do_ need flags, you can pass them to `regex` first:

```ts
const myCaseInsensitiveRegex = regex('i')`
    ^
        abc

        ${myFancyRegex}  # seamlessly interpolate other regexes
 
        \w\d\b\0\\       # look Mom, no double escaping! 
        ... 
        \r\n\t\x20       # use "\x20" to match a literal space
    $
`
```

The compiled regex here is `/^abc.{5}\w\d\b\0\\...\r\n\t\x20$/i` — hopefully you’ll agree that the commented and indented version is a lot more readable!

If you like, you can pass the the flags in an options object instead:

```ts
const myRegexWithOptions = regex({
	unicode: true,
	global: true,
})`
    ^
        💩+    # with unicode enabled, this matches by codepoint
    $
`
```

Here, the compiled regex is `/^💩+$/gu`.

Because fancy-regex uses the raw template string under the hood, the only things you’ll need to escape that you wouldn’t in a regex literal are backticks (`` ` ``) and the sequence `${`. Whitespace and hash symbols (`#`) must also be escaped if you don’t want them to be removed.

On the flipside, you no longer need to escape forward-slashes, which makes URL matching even easier than before!

```ts
regex`https://dev\.to/top/(week|month)`
// compiles to /https:\/\/dev\.to\/top\/(week|month)/
```

This is the first npm package I’ve ever published, so I’d love to hear your feedback on v0.X.X! 🧡🧡🧡
* [npm package](https://www.npmjs.com/package/fancy-regex)
* [GitHub repo](https://github.com/lionel-rowe/fancy-regex)