From 8753824209328827882b9e5c304f9b8a79ca42b9 Mon Sep 17 00:00:00 2001 From: Steven Levithan Date: Mon, 22 Jul 2024 23:29:33 +0200 Subject: [PATCH] Subroutines: Avoid adding captures if no backrefs (part 2) --- README.md | 1 + src/subroutines.js | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0e06a56..0ff51e2 100644 --- a/README.md +++ b/README.md @@ -227,6 +227,7 @@ See the next section on definition groups for another way to do this. - Subroutines can appear before the groups they reference, as shown in examples above. - If there are [duplicate capture names](https://github.com/tc39/proposal-duplicate-named-capturing-groups), subroutines refer to the first instance of the given group (matching the behavior of PCRE and Perl). - Although subroutines can be chained to any depth, a descriptive error is thrown if they're used recursively. Support for recursion can be added via an extension (see [*Recursion*](#recursion)). +- Like backreferences, subroutines can't be used from *within* character classes. - As with all new syntax in `regex`, subroutines are applied after interpolation, giving them maximal flexibility. diff --git a/src/subroutines.js b/src/subroutines.js index 9817226..6e83c1d 100644 --- a/src/subroutines.js +++ b/src/subroutines.js @@ -89,11 +89,12 @@ function processSubroutines(expression, namedGroups) { if (openSubroutinesMap.size) { // Named capturing group if (m !== '(') { - // Replace named with unnamed capture. Subroutines shouldn't create new captures, but - // it can't be helped since we need any backrefs to this named capture to work. Given - // that implicit flag n prevents unnamed capture and requires you to rely on named - // backrefs and `groups`, this essentially accomplishes not creating a capture - result = spliceStr(result, index, m, '('); + // Replace named with unnamed capture. Subroutines ideally wouldn't create any new + // captures, but it can't be helped since we need any backrefs to this named capture to + // work. Given that flag n prevents unnamed capture and thereby requires you to rely on + // named backrefs and `groups`, switching to unnamed essentially accomplishes not + // creating a capture. Fully avoid capturing if there are no backrefs in the expression + result = spliceStr(result, index, m, '(' + (hasBackrefs ? '' : '?:')); token.lastIndex -= m.length; } backrefIncrements.push(lastOf(backrefIncrements) + subroutine.numCaptures);