diff --git a/README.md b/README.md index 864f76e..c7da631 100644 --- a/README.md +++ b/README.md @@ -553,6 +553,7 @@ Notice that nearly every feature below has at least subtle differences from Java ✅ ✔ Unescaped - outside of range is literal in some contexts (different than JS rules in any mode)
+ ✔ Error for unescaped [ that doesn't form nested class
✔ Fewer chars require escaping than JS
diff --git a/spec/match-group.spec.js b/spec/match-group.spec.js index 1f7d24f..099fa17 100644 --- a/spec/match-group.spec.js +++ b/spec/match-group.spec.js @@ -5,23 +5,65 @@ beforeEach(() => { jasmine.addMatchers(matchers); }); -// TODO: Add me -// describe('Group', () => { -// describe('atomic', () => { -// it('should', () => { -// expect('').toExactlyMatch(r``); -// }); -// }); - -// describe('flags', () => { -// it('should', () => { -// expect('').toExactlyMatch(r``); -// }); -// }); - -// describe('noncapturing', () => { -// it('should', () => { -// expect('').toExactlyMatch(r``); -// }); -// }); -// }); +describe('Group', () => { + describe('atomic', () => { + it('should not remember backtracking positions within atomic groups', () => { + expect('abc').not.toFindMatch(`a(?>bc|b)c`); + expect('abcc').toExactlyMatch(`a(?>bc|b)c`); + expect('aaaaaab').not.toFindMatch(`(?>a+)ab`); + expect('aaaaaab').toExactlyMatch(`(?>a)+ab`); + }); + + it('should allow quantifying atomic groups', () => { + expect('one two').toExactlyMatch(r`(?>\w+\s?)+`); + }); + + it('should work for multiple atomic groups', () => { + expect('ab').toExactlyMatch(`(?>a)(?>b)`); + }); + + it('should work for nested atomic groups', () => { + expect('integerrr+').toExactlyMatch(r`\b(?>int(?>eger+)?|insert)\b(?>.)`); + expect('integerrr+').not.toFindMatch(r`\b(?>int(?>eger+)??|insert)\b(?>.)`); + }); + + it('should work when named capturing groups present', () => { + expect('abcc').toExactlyMatch(`(?)a(?>bc|b)c`); + expect('abc').not.toFindMatch(`(?)a(?>bc|b)c`); + expect('abcc').toExactlyMatch(`a(?>(?)bc|b)c`); + expect('abc').not.toFindMatch(`a(?>(?)bc|b)c`); + }); + + it('should work when unnamed capturing groups present', () => { + expect('abcc').toExactlyMatch(`()a(?>bc|b)c`); + expect('abc').not.toFindMatch(`()a(?>bc|b)c`); + expect('abcc').toExactlyMatch(`a(?>()bc|b)c`); + expect('abc').not.toFindMatch(`a(?>()bc|b)c`); + }); + + it('should work with numbered backreferences', () => { + expect('aax').toExactlyMatch(r`(a)\1(?>x)`); + expect('xaa').toExactlyMatch(r`(?>x(a)\1)`); + expect('xaa').toExactlyMatch(r`(?>x)(a)\1`); + expect('aaabababcabc').toExactlyMatch(r`(a)\1(?>\1(b)\1\2(?>\1\2))(c)\1\2\3`); + }); + + it('should handle regression cases', () => { + expect('[').toExactlyMatch(r`(?>[\[])`); + }); + }); + + // TODO: Add me + // describe('flags', () => { + // it('should', () => { + // expect('').toExactlyMatch(r``); + // }); + // }); + + // TODO: Add me + // describe('noncapturing', () => { + // it('should', () => { + // expect('').toExactlyMatch(r``); + // }); + // }); +}); diff --git a/src/generate.js b/src/generate.js index c9890ef..5707306 100644 --- a/src/generate.js +++ b/src/generate.js @@ -180,6 +180,9 @@ const BaseEscapeChars = new Set([ ]); const CharClassEscapeChars = new Set([ '-', '\\', ']', '^', + // Literal `[` doesn't require escaping with flag u, but this can help work around regex source + // linters and regex syntax processors that expect unescaped `[` to create a nested class + '[', ]); const CharClassEscapeCharsFlagV = new Set([ '(', ')', '-', '/', '[', '\\', ']', '^', '{', '|', '}',