HiveBrain v1.2.0
Get Started
← Back to all entries
snippetjavascriptTip

Implementing a library for readable regular expressions in JavaScript

Submitted by: @import:30-seconds-of-code··
0
Viewed 0 times
javascriptimplementingreadableexpressionsregularlibraryfor

Problem

In the last two articles, I've touched upon using TDD to kickstart a small project and designing a user-centric API. Now, it's time to implement the API we've designed!
Let's quickly recap the decisions we've made in terms of the project and the API so far. The project itself is a simplified, readable and reusable API on top of the regular expression <dfn title="A domain-specific language (DSL) is a computer language specialized to a particular application domain. This is in contrast to a general-purpose language (GPL), which is broadly applicable across domains.">DSL</dfn>, developed using the <dfn title="Test-driven development (TDD) is a software development process relying on software requirements being converted to test cases before software is fully developed.">TDD</dfn> approach.
The API is designed with users somewhat familiar with RegEx in mind, moving towards a more natural language approach. The interface will use simple naming, <dfn title="A variadic function is a function of indefinite arity, i.e., one which accepts a variable number of arguments.">variadic functions</dfn> and named arguments for special cases, such as named groups, lookaheads or quantifier counts. Finally, we'll export a function that will accept an array of patterns and a flags object, and return a regular expression object.
For the API implementation, I'll once again focus on the decision-making part of the process. The implementation is either trivial or too complex, depending on your skill level and experience. I'll try to explain the reasoning behind the decisions I make, rather than the code itself, which can be browsed through on the GitHub repository.
> [!NOTE]

Solution

This class had a simple job: processing any valid value (`Segment`, `RegExp` or `string`) into a `Segment` object with a `value` property. This would allow me to build a regular expression by combining multiple `Segment` objects.

#### Using native structures

After a little fiddling around, I came to realize that my `Segment` class should, in fact, subclass `RegExp` itself. This meant that its `value` was roughly equivalent to `RegExp.prototype.source`. This change made the class simpler and more intuitive.


The API is designed with users somewhat familiar with RegEx in mind, moving towards a more natural language approach. The interface will use simple naming, <dfn title="A variadic function is a function of indefinite arity, i.e., one which accepts a variable number of arguments.">variadic functions</dfn> and named arguments for special cases, such as named groups, lookaheads or quantifier counts. Finally, we'll export a function that will accept an array of patterns and a flags object, and return a regular expression object.
For the API implementation, I'll once again focus on the decision-making part of the process. The implementation is either trivial or too complex, depending on your skill level and experience. I'll try to explain the reasoning behind the decisions I make, rather than the code itself, which can be browsed through on the GitHub repository.
> [!NOTE]
>
> Some of the code in this article is simplified (e.g. no error handling) for brevity. Filling in the gaps isn't particularly hard, if you're trying to recreate the project yourself.
My initial approach hinged on creating a pattern class that could be used to build regular expressions. This approach assumed that any pattern should be possible to test on its own (thus making TDD more feasible). Therefore, I started with a Segment class (maybe the name wasn't perfect) that would represent a single pattern segment.

Code Snippets

This class had a simple job: processing any valid value (`Segment`, `RegExp` or `string`) into a `Segment` object with a `value` property. This would allow me to build a regular expression by combining multiple `Segment` objects.

#### Using native structures

After a little fiddling around, I came to realize that my `Segment` class should, in fact, subclass `RegExp` itself. This meant that its `value` was roughly equivalent to `RegExp.prototype.source`. This change made the class simpler and more intuitive.
This would now allow me to tackle the problem of **testing individual patterns**, as every `Segment` could take the place of a regular expression. Therefore, the tests I had in place at the time would pass with flying colors:
#### Sanitization & conversion

One core thing I had to deal with early on was **string sanitization**. Luckily, it's a simple matter of finding and replacing special characters. However, I'd also need to create segments without some escapes (e.g. `+` or `*` when building quantifiers later on).

Context

From 30-seconds-of-code: tdd-library-implementation-with-vite-vitest

Revisions (0)

No revisions yet.