Skip to content

Commit

Permalink
Add XRegExp.tag in build plugin for tagged template string construc…
Browse files Browse the repository at this point in the history
…tion

Fixes slevithan/xregexp#103
  • Loading branch information
speecyy committed Apr 25, 2017
1 parent 8c884af commit a8a9b5f
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 0 deletions.
24 changes: 24 additions & 0 deletions src/addons/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,30 @@ module.exports = function(XRegExp) {
XRegExp(value, flags);
}

/**
* Provides a tag function for building regexes using template literals [1]. See GitHub issue
* 103 for discussion [2].
*
* [1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_template_literals
* [2]: https://github.com/slevithan/xregexp/issues/103
*/
XRegExp.tag = function (flags) {
return function tag (literals /*, ...substitutions */) {
var substitutions = [].slice.call(arguments, 1);
var subpatterns = substitutions.concat('').map(interpolate);
var pattern = literals.raw.map(embedSubpatternAfter).join('');
return XRegExp.build(pattern, subpatterns, flags);
};

function interpolate (substitution) {
return substitution instanceof RegExp ? substitution : XRegExp.escape(substitution);
}

function embedSubpatternAfter (raw, subpatternIndex) {
return raw + '{{' + subpatternIndex + '}}';
}
};

/**
* Builds regexes using named subpatterns, for readability and pattern reuse. Backreferences in
* the outer pattern and provided subpatterns are automatically renumbered to work correctly.
Expand Down
76 changes: 76 additions & 0 deletions tests/spec/s-addons-build.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,81 @@
describe('XRegExp.build addon:', function() {

describe('XRegExp.tag()', function() {

it('should escape the metacharacters of interpolated strings', function() {
var inner = '.html'
var re = XRegExp.tag()`^index${inner}$`;

expect(re.test('index.html')).toBe(true);
expect(re.test('index-html')).toBe(false);
});

it('should rewrite the backreferences of interpolated regexes', function() {
var inner = /(.)\1/;
var re = XRegExp.tag()`^${inner}${inner}$`;

expect(re.test('aabb')).toBe(true);
expect(re.test('aaba')).toBe(false);
});

it('should treat interpolated strings as atomic tokens', function() {
var inner = 'ab';
var re = XRegExp.tag()`^${inner}+$`;

expect(re.test('abab')).toBe(true);
expect(re.test('abb')).toBe(false);
});

it('should treat interpolated regexes as atomic tokens', function() {
var inner = /ab/;
var re = XRegExp.tag()`^${inner}+$`;

expect(re.test('abab')).toBe(true);
expect(re.test('abb')).toBe(false);
});

it('should support the "x" flag', function() {
var inner = /ab/;
var re = XRegExp.tag('x')`
^
${inner}
+
$
`;

expect(re.test('abab')).toBe(true);
expect(re.test('abb')).toBe(false);
});

it('should support the "n" flag', function() {
var inner = XRegExp('(unnamed), (?<name>named)');
var re = XRegExp.tag('n')`${inner}`;

expect(re.exec('unnamed, named')[1]).toBe('named');
});

it('should support the "g" flag', function() {
var inner = 'a';
var re = XRegExp.tag('g')`${inner}`;

expect('aaa'.match(re)).toEqual(['a', 'a', 'a']);
});

it('should allow `false` to be interpolated', function() {
var inner = false;
var re = XRegExp.tag()`^${inner}$`;

expect(re.test('false')).toBe(true);
});

it('should allow unescaped character classes', function() {
var re = XRegExp.tag()`\d`;

expect(re.test('1')).toBe(true);
});

});

describe('XRegExp.build()', function() {

it('should apply a mode modifier in the outer pattern to the full regex with interpolated values', function() {
Expand Down

0 comments on commit a8a9b5f

Please sign in to comment.