/regexp-template-core

A JavaScript library to generate complex regular expressions more easily.

Primary LanguageJavaScriptMIT LicenseMIT

RegExpTemplate

A JavaScript library to generate complex regular expressions more easily.

npm version Conventional Commits

⚠️ WARNING: This library still under development and should not be used in production!

Contributing

Want to help? Found a bug or have any suggestion? Find how to contribute in the CONTRIBUTING.md file.

Getting Started

Add to your project

The library can be used in the browser using the CDN:

<script src="https://cdn.jsdelivr.net/npm/@regexp-template/core/dist/regexp-template.min.js"></script>

or via npm:

npm i @regexp-template/core

Using the script tag the RegExpTemplate class becomes available on the global scope.

On Node.js can be required using:

const RegExpTemplate = require('@regexp-template/core');

Hello world example

Lets start with a simple example: concatenation of two regular expressions, /hello/ and /world/.

We first create a RegExpTemplate instance with our regular expressions as arguments:

var hwTemplate = new RegExpTemplate(/hello/, /world/);

then we can compile our template to a RegExp:

var re = hwTemplate.compile();
// outputs /helloworld/

The compile method joins the two regular expressions into a new one.

In this case we only passed two regular expressions but you can pass as many template elements (see below) as you want.

Template Elements

The template is constructed using pieces called elements. In the hello world example above, /hello/ and /world/ are two elements of that template.

Template elements have 4 types:

  • RegExp - used to add regular expression segments to the template. Also allow use of template variables.

  • string - all characters are interpreted as literal characters (except especials characters of strings like \n).

  • RegExpTemplate - this allows templates to be used inside another templates. See the subtemplates section.

  • extension - a custom user defined class. See the template extension section for more info.

Any other type passed to the template gets converted to a string.

Template Variables

Template Variables let you introduce new template elements inside of regular expressions.

Declaring variables

Template variables can be declared by using the notation \VAR{varname} inside regular expressions, where the varname is the name of the variable.

Note that in \VAR doesn't need to be uppercase. '\VAR', \Var or \var all work the same way.

In the code below a template is created and a variable called myVar is defined.

new RegExpTemplate(/\VAR{ myVar }/);

Note: whitespace can be used inside the curly braces.

variables are unique, any reference to varname refers to the same variable.

new RegExpTemplate(
  /\VAR{ foo } is the/,
  /same as \VAR{ foo } but not \VAR{ bar }/
);

Assigning values

Once defined a variable can then be assigned. This is done using the applyVars method.

const myTemplate = new RegExpTemplate(/\VAR{ myVar }/);

myTemplate.applyVars({
  myVar: "myValue"
});

The applyVars method expects an object that maps the name of the template variable to its value.

The value can be any template element.

After the method is called then all references of the variables passed are going to be replaced by the corresponding value.

const myTemplate = 
new RegExpTemplate(
  /\VAR{ foo } is the/,
  /same as \VAR{ foo } but not \VAR{ bar }/
);

myTemplate.applyVars({
  foo: "dog",
  bar: "cat"
});

myTemplate.compile();
// outputs /dog is the same as dog but not cat/

You don't need to set variables at once. you can do something like:

myTemplate.applyVars({foo: "dog"});
myTemplate.applyVars({bar: "cat"});

or in chain:

myTemplate
.applyVars({foo: "dog"})
.applyVars({bar: "cat"});

keep in mind however that all variables must be assigned before compiling the template:

const myTemplate = new RegExpTemplate(
  /\VAR{ myVar } was not assigned/
);

myTemplate.compile();
// throws an error because 'myVar' is not assigned

New variable reference in assign.

If you assign a value that contains new variables, that variable will be defined/referenced once the variable is applied.

const myTemplate = new RegExpTemplate(
  /\VAR{ oldVar }/
);

myTemplate
.applyVars({oldVar: /\(\VAR{ newVar }\)/})
.applyVars({newVar: '2'});

In the example above a regular expression defines a variable called oldVar.

The first applyVars call replaces the oldVar by a new Regular Expression that contains a variable reference wrapped in parentesis.

Once added to the template the new variable newVar is defined.

Then the second applyVars replaces newVar with the string '2'.

Since all variables (oldVar and newVar) defined are assigned, the template can now be compiled.

myTemplate.compile();
// outputs /(2)/

Subtemplates

Templates can be included inside other templates.

// this template might be more complex
// but we keep it simple for the example
const numberTemplate = new RegExpTemplate(/\d+\.\d*/);

// parent template using the numberTemplate
const sumTemplate = new RegExpTemplate(
  numberTemplate, ' + ', numberTemplate
);

sumTemplate.compile();
// outputs /\d+\.\d* \+ \d+\.\d*/

This allows you split parts of a complex regular expression into smaller ones, making it easier to read and edit. It also allows the reuse of these smaller parts in different contexts that might be common e.g. the number template in the example above might be used in other contexts than sum.

The subtemplates are independent. The template variables assigned to the parent template will not propagate to the subtemplate.

When the parent template compile method is called the subtemplate compile method is called as well and used to compute the result of the parent. This means that the subtemplate must be ready to compile when the compile is called on the parent (see template variables).

Template Extensions

This feature is not implemented yet.

The RegExpTemplate provides an API that allows you to make your own template elements.

Licence

MIT