From 0e93aff51dd8395591740ed125e7803140aefcc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Wed, 24 Aug 2022 18:21:57 +0200 Subject: [PATCH] Avoid calling regexpu for duplicated named groups when not necessary --- .../src/index.ts | 23 ++++--------------- .../src/util.ts | 23 ++++++++++++++++--- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/packages/babel-helper-create-regexp-features-plugin/src/index.ts b/packages/babel-helper-create-regexp-features-plugin/src/index.ts index d1be9056db04..52b9e2188d28 100644 --- a/packages/babel-helper-create-regexp-features-plugin/src/index.ts +++ b/packages/babel-helper-create-regexp-features-plugin/src/index.ts @@ -95,18 +95,18 @@ export function createRegExpFeaturePlugin({ const features = file.get(featuresKey); const runtime = file.get(runtimeKey) ?? true; - const regexpuOptions = generateRegexpuOptions(features); - if (canSkipRegexpu(node, regexpuOptions)) return; + const regexpuOptions = generateRegexpuOptions(node.pattern, features); + if (canSkipRegexpu(node, regexpuOptions)) { + return; + } const namedCaptureGroups: Record = { __proto__: null, }; - let hasDuplicateNamedCaptureGroups = false; if (regexpuOptions.namedGroups === "transform") { regexpuOptions.onNamedGroup = (name, index) => { const prev = namedCaptureGroups[name]; if (typeof prev === "number") { - hasDuplicateNamedCaptureGroups = true; namedCaptureGroups[name] = [prev, index]; } else if (Array.isArray(prev)) { prev.push(index); @@ -116,20 +116,7 @@ export function createRegExpFeaturePlugin({ }; } - let pattern = rewritePattern(node.pattern, node.flags, regexpuOptions); - if ( - !hasDuplicateNamedCaptureGroups && - hasFeature(features, FEATURES.duplicateNamedCaptureGroups) && - !hasFeature(features, FEATURES.namedCaptureGroups) - ) { - // If we only transformed named groups because we want to transform duplicates - // but there are no duplicates, re-transform the regexp without transforming - // named groups. - regexpuOptions.namedGroups = false; - if (canSkipRegexpu(node, regexpuOptions)) return; - pattern = rewritePattern(node.pattern, node.flags, regexpuOptions); - } - node.pattern = pattern; + node.pattern = rewritePattern(node.pattern, node.flags, regexpuOptions); if ( regexpuOptions.namedGroups === "transform" && diff --git a/packages/babel-helper-create-regexp-features-plugin/src/util.ts b/packages/babel-helper-create-regexp-features-plugin/src/util.ts index 0648767f53dc..d879f0a14e70 100644 --- a/packages/babel-helper-create-regexp-features-plugin/src/util.ts +++ b/packages/babel-helper-create-regexp-features-plugin/src/util.ts @@ -3,7 +3,10 @@ import { FEATURES, hasFeature } from "./features"; import type { RegexpuOptions } from "regexpu-core"; -export function generateRegexpuOptions(toTransform: number): RegexpuOptions { +export function generateRegexpuOptions( + pattern: string, + toTransform: number, +): RegexpuOptions { type Experimental = 1; const feat = ( @@ -13,6 +16,21 @@ export function generateRegexpuOptions(toTransform: number): RegexpuOptions { return hasFeature(toTransform, FEATURES[name]) ? ok : false; }; + const featDuplicateNamedGroups = (): "transform" | false => { + if (!feat("duplicateNamedCaptureGroups")) return false; + + // This can return false positive, for example for /\(?\)/. + // However, it's such a rare occurrence that it's ok to compile + // the regexp even if we only need to compile regexps with + // duplicate named capturing groups. + const regex = /\(\?<([^>]+)>/g; + const seen = new Set(); + for (let match; (match = regex.exec(pattern)); seen.add(match[1])) { + if (seen.has(match[1])) return "transform"; + } + return false; + }; + return { unicodeFlag: feat("unicodeFlag"), unicodeSetsFlag: @@ -20,8 +38,7 @@ export function generateRegexpuOptions(toTransform: number): RegexpuOptions { feat("unicodeSetsFlag_syntax", "parse"), dotAllFlag: feat("dotAllFlag"), unicodePropertyEscapes: feat("unicodePropertyEscape"), - namedGroups: - feat("namedCaptureGroups") || feat("duplicateNamedCaptureGroups"), + namedGroups: feat("namedCaptureGroups") || featDuplicateNamedGroups(), onNamedGroup: () => {}, }; }