Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BREAKING: Handle ES2018 capture names #247

Merged
merged 14 commits into from Jan 9, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
80 changes: 2 additions & 78 deletions tests/spec/s-xregexp-methods.js
Expand Up @@ -1251,84 +1251,8 @@ describe('XRegExp.replace()', function() {
expect(function() {XRegExp.replace('test', XRegExp('(?<test>t)', 'g'), ':$<x>:');}).toThrowError(SyntaxError);
});

});

describe('explicit numbered backreferences', function() {
josephfrazier marked this conversation as resolved.
Show resolved Hide resolved

it('should return the numbered backreference', function() {
expect(XRegExp.replace('test', /(.)./g, '${1}')).toBe('ts');
expect(XRegExp.replace('test', /(.)./g, '$<1>')).toBe('ts');

// Backreference to a nonparticipating capturing group
expect(XRegExp.replace('test', /t|(e)/g, '${1}')).toBe('es');
expect(XRegExp.replace('test', /t|(e)/g, '$<1>')).toBe('es');
});

it('should allow leading zeros', function() {
expect(XRegExp.replace('test', /(.)./g, '${01}')).toBe('ts');
expect(XRegExp.replace('test', /(.)./g, '$<01>')).toBe('ts');

expect(XRegExp.replace('test', /(.)./g, '${001}')).toBe('ts');
expect(XRegExp.replace('test', /(.)./g, '$<001>')).toBe('ts');
});

it('should return named backreferences by number', function() {
expect(XRegExp.replace('test', XRegExp('(?<name>.).', 'g'), '${1}')).toBe('ts');
expect(XRegExp.replace('test', XRegExp('(?<name>.).', 'g'), '$<1>')).toBe('ts');
});

it('should separate numbered backreferences from following literal digits', function() {
expect(XRegExp.replace('test', new RegExp('(.).', 'g'), '${1}0')).toBe('t0s0');
expect(XRegExp.replace('test', new RegExp('(.).', 'g'), '$<1>0')).toBe('t0s0');

expect(XRegExp.replace('test', new RegExp('(.).' + '()'.repeat(9), 'g'), '${1}0')).toBe('t0s0');
expect(XRegExp.replace('test', new RegExp('(.).' + '()'.repeat(9), 'g'), '$<1>0')).toBe('t0s0');
});

it('should throw an exception for backreferences to unknown group numbers', function() {
expect(function() {XRegExp.replace('test', /t/, '${1}');}).toThrowError(SyntaxError);
expect(function() {XRegExp.replace('test', /t/, '$<1>');}).toThrowError(SyntaxError);

expect(function() {XRegExp.replace('test', /(t)/, '${2}');}).toThrowError(SyntaxError);
expect(function() {XRegExp.replace('test', /(t)/, '$<2>');}).toThrowError(SyntaxError);
});

it('should allow ${0} to refer to the entire match', function() {
expect(XRegExp.replace('test', /../g, '${0}:')).toBe('te:st:');
expect(XRegExp.replace('test', /../g, '$<0>:')).toBe('te:st:');

expect(XRegExp.replace('test', /../g, '${00}:')).toBe('te:st:');
expect(XRegExp.replace('test', /../g, '$<00>:')).toBe('te:st:');

expect(XRegExp.replace('test', /../g, '${000}:')).toBe('te:st:');
expect(XRegExp.replace('test', /../g, '$<000>:')).toBe('te:st:');
});

it('should support backreferences 100 and greater, if the browser does natively', function() {
// IE < 9 doesn't allow backreferences greater than \99 *within* a regex, but
// XRegExp still allows backreferences to groups 100+ within replacement text
try {
// Regex with 1,000 capturing groups. This fails in Firefox 4-6 (but not v3.6
// or v7+) with `InternalError: regular expression too complex`
var lottaGroups = new RegExp([
'^(a)\\1', '()'.repeat(8),
'(b)\\10', '()'.repeat(89),
'(c)', '()'.repeat(899),
'(d)$'
].join(''));

expect(XRegExp.replace('aabbcd', lottaGroups, '${0} ${01} ${001} ${0001} ${1} ${10} ${100} ${1000}')).toBe('aabbcd a a a a b c d');
expect(XRegExp.replace('aabbcd', lottaGroups, '$<0> $<01> $<001> $<0001> $<1> $<10> $<100> $<1000>')).toBe('aabbcd a a a a b c d');
expect(XRegExp.replace('aabbcd', lottaGroups, '$<0> ${01} $<001> ${0001} $<1> ${10} $<100> ${1000}')).toBe('aabbcd a a a a b c d');
// For comparison...
expect(XRegExp.replace('aabbcd', lottaGroups, '$0 $01 $001 $0001 $1 $10 $100 $1000')).toBe('aabbcd a aabbcd1 aabbcd01 a b b0 b00');
} catch (err) {
// Keep the assertion count consistent cross-browser
expect(true).toBe(true);
expect(true).toBe(true);
expect(true).toBe(true);
expect(true).toBe(true);
}
it('should not allow leading digits', function() {
expect(function() {XRegExp.replace('test', /(.)./g, '${01}');}).toThrowError(SyntaxError);
josephfrazier marked this conversation as resolved.
Show resolved Hide resolved
});

});
Expand Down
62 changes: 10 additions & 52 deletions tests/spec/s-xregexp.js
Expand Up @@ -393,27 +393,24 @@ describe('XRegExp()', function() {
// Named capture *functionality* is tested by the specs for named backreference syntax,
// XRegExp.exec, XRegExp.replace, etc.

it('should allow the characters A-Z, a-z, 0-9, $, and _ to be used in capture names', function() {
it('should allow the characters A-Z, a-z, 0-9, $, _, and RegExpIdentifierName characters to be used in capture names', function() {
josephfrazier marked this conversation as resolved.
Show resolved Hide resolved
expect(XRegExp('(?<Az>x)').test('x')).toBe(true);
expect(XRegExp('(?<_09>x)').test('x')).toBe(true);
expect(XRegExp('(?<$>x)').test('x')).toBe(true);
expect(function() {XRegExp('(?<naïve>)');}).not.toThrow();
expect(function() {XRegExp('(?<Русский>)');}).not.toThrow();
expect(function() {XRegExp('(?<日本語>)');}).not.toThrow();
josephfrazier marked this conversation as resolved.
Show resolved Hide resolved
});

it('should throw an exception if characters other than A-Z, a-z, 0-9, $, and _ are used in capture names', function() {
josephfrazier marked this conversation as resolved.
Show resolved Hide resolved
expect(function() {XRegExp('(?<?>)');}).toThrowError(SyntaxError);
expect(function() {XRegExp('(?<.>)');}).toThrowError(SyntaxError);
expect(function() {XRegExp('(?<<>)');}).toThrowError(SyntaxError);
expect(function() {XRegExp('(?<->)');}).toThrowError(SyntaxError);
// Native named capture uses different allowed chars that XRegExp should be updated to handle
//expect(function() {XRegExp('(?<naïve>)');}).toThrowError(SyntaxError);
//expect(function() {XRegExp('(?<Русский>)');}).toThrowError(SyntaxError);
//expect(function() {XRegExp('(?<日本語>)');}).toThrowError(SyntaxError);
});

it('should allow capture names to start with digits', function() {
expect(XRegExp('(?<0a>x)').test('x')).toBe(true);
expect(XRegExp('(?<1_1>x)').test('x')).toBe(true);
expect(XRegExp('(?<234$>x)').test('x')).toBe(true);
it('should not allow capture names to start with digits', function() {
expect(function() {XRegExp('(?<0a>x)');}).toThrowError(SyntaxError);
});

it('should throw an exception if bare integers are used as capture names', function() {
Expand Down Expand Up @@ -488,6 +485,10 @@ describe('XRegExp()', function() {
expect(function() {XRegExp('\\k<`>');}).toThrowError(SyntaxError);
});

it('should not allow leading digits', function() {
expect(function() {XRegExp('(.)\\k<01>');}).toThrowError(SyntaxError);
josephfrazier marked this conversation as resolved.
Show resolved Hide resolved
});

it('should separate backreferences from following literal digits', function() {
expect(XRegExp('(?<$1>A1)(2)(3)(4)(5)(6)(7)(8)(9)(B10)\\k<$1>0').test('A123456789B10A10')).toBe(true);
expect(XRegExp('(?<$1>A)\\k<$1>2').test('AA2')).toBe(true);
Expand All @@ -506,49 +507,6 @@ describe('XRegExp()', function() {

});

describe('explicit numbered backreferences', function() {
josephfrazier marked this conversation as resolved.
Show resolved Hide resolved

it('should match the numbered backreference', function() {
expect(XRegExp('(.)\\k<1>').test('aa')).toBe(true);
expect(XRegExp('(.)\\k<1>').test('ab')).toBe(false);
expect(XRegExp('(.)\\k<1>\\k<1>').test('aaa')).toBe(true);
});

it('should allow leading zeros', function() {
expect(XRegExp('(.)\\k<01>').test('aa')).toBe(true);
expect(XRegExp('(.)\\k<001>').test('aa')).toBe(true);
});

it('should match named backreferences by number', function() {
expect(XRegExp('(?<A>.)\\k<1>').test('aa')).toBe(true);
expect(XRegExp('(?<A>.)\\k<1>').test('ab')).toBe(false);
expect(XRegExp('(?<A>.)\\k<1>\\k<1>').test('aaa')).toBe(true);
});

it('should separate numbered backreferences from following literal digits', function() {
expect(XRegExp('(A1)(2)(3)(4)(5)(6)(7)(8)(9)(B10)\\k<1>0').test('A123456789B10A10')).toBe(true);
expect(XRegExp('(A)\\k<1>2').test('AA2')).toBe(true);
});

it('should throw an exception for backreferences to unknown groups', function() {
expect(function() {XRegExp('\\k<1>');}).toThrowError(SyntaxError);
expect(function() {XRegExp('()\\k<2>');}).toThrowError(SyntaxError);
});

it('should throw an exception for backreferences to capturing groups not opened to the left', function() {
expect(function() {XRegExp('\\k<1>()');}).toThrowError(SyntaxError);
expect(function() {XRegExp('()\\k<2>()');}).toThrowError(SyntaxError);
expect(function() {XRegExp('(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)\\k<11>(11)');}).toThrowError(SyntaxError);
expect(function() {XRegExp('(\\k<1>)');}).not.toThrow();
});

it('should not allow \\k<0> to refer to the entire match', function() {
expect(function() {XRegExp('\\k<0>');}).toThrowError(SyntaxError);
expect(function() {XRegExp('\\k<00>');}).toThrowError(SyntaxError);
});

});

describe('strict error handling', function() {

it('should throw an exception for octals except \\0 not followed by 0-9', function() {
Expand Down