From 47fd199465e2fe324415e21350777ce9ea529f93 Mon Sep 17 00:00:00 2001 From: Sumukh L Date: Wed, 29 Jul 2026 15:44:36 +0530 Subject: [PATCH] Gate ES2025 regex syntax (duplicate named groups, pattern modifiers) behind target check Fixes #63682 --- src/compiler/diagnosticMessages.json | 8 ++++++++ src/compiler/scanner.ts | 6 ++++++ ...DuplicateNamedGroups(target=es2022).errors.txt | 11 +++++++++++ ...fiersAndDuplicateNamedGroups(target=es2022).js | 10 ++++++++++ ...AndDuplicateNamedGroups(target=es2022).symbols | 9 +++++++++ ...rsAndDuplicateNamedGroups(target=es2022).types | 15 +++++++++++++++ ...fiersAndDuplicateNamedGroups(target=es2025).js | 10 ++++++++++ ...AndDuplicateNamedGroups(target=es2025).symbols | 9 +++++++++ ...rsAndDuplicateNamedGroups(target=es2025).types | 15 +++++++++++++++ ...arExpressionScanning(target=es2015).errors.txt | 14 +++++++++++++- ...gularExpressionScanning(target=es5).errors.txt | 14 +++++++++++++- ...egexPatternModifiersAndDuplicateNamedGroups.ts | 4 ++++ 12 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2022).errors.txt create mode 100644 tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2022).js create mode 100644 tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2022).symbols create mode 100644 tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2022).types create mode 100644 tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2025).js create mode 100644 tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2025).symbols create mode 100644 tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2025).types create mode 100644 tests/cases/conformance/es2025/regexPatternModifiersAndDuplicateNamedGroups.ts diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 17586e927d0ac..e4f5b82c44610 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1724,6 +1724,14 @@ "category": "Error", "code": 1515 }, + "Regular expression pattern modifiers are only available when targeting '{0}' or later.": { + "category": "Error", + "code": 18062 + }, + "Duplicate named capturing groups are only available when targeting '{0}' or later.": { + "category": "Error", + "code": 18063 + }, "A character class range must not be bounded by another character class.": { "category": "Error", "code": 1516 diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index c4e20bb055e28..5eafe711d1dc7 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -2750,6 +2750,9 @@ export function createScanner( error(Diagnostics.Subpattern_flags_must_be_present_when_there_is_a_minus_sign, start, pos - start); } } + if (pos !== start && languageVersion < ScriptTarget.ES2025) { + error(Diagnostics.Regular_expression_pattern_modifiers_are_only_available_when_targeting_0_or_later, start, pos - start, getNameOfScriptTarget(ScriptTarget.ES2025)); + } scanExpectedChar(CharacterCodes.colon); isPreviousTermQuantifiable = true; break; @@ -3008,6 +3011,9 @@ export function createScanner( error(Diagnostics.Named_capturing_groups_with_the_same_name_must_be_mutually_exclusive_to_each_other, tokenStart, pos - tokenStart); } else { + if (groupSpecifiers?.has(tokenValue) && languageVersion < ScriptTarget.ES2025) { + error(Diagnostics.Duplicate_named_capturing_groups_are_only_available_when_targeting_0_or_later, tokenStart, pos - tokenStart, getNameOfScriptTarget(ScriptTarget.ES2025)); + } topNamedCapturingGroupsScope ??= new Set(); topNamedCapturingGroupsScope.add(tokenValue); groupSpecifiers ??= new Set(); diff --git a/tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2022).errors.txt b/tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2022).errors.txt new file mode 100644 index 0000000000000..00cff418a8b35 --- /dev/null +++ b/tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2022).errors.txt @@ -0,0 +1,11 @@ +regexPatternModifiersAndDuplicateNamedGroups.ts(1,47): error TS18063: Duplicate named capturing groups are only available when targeting 'es2025' or later. +regexPatternModifiersAndDuplicateNamedGroups.ts(2,22): error TS18062: Regular expression pattern modifiers are only available when targeting 'es2025' or later. + + +==== regexPatternModifiersAndDuplicateNamedGroups.ts (2 errors) ==== + const dupNames = /(?\d{4})-\d{2}|\d{2}\/(?\d{4})/; + ~ +!!! error TS18063: Duplicate named capturing groups are only available when targeting 'es2025' or later. + const modifiers = /(?i:abc)/; + ~ +!!! error TS18062: Regular expression pattern modifiers are only available when targeting 'es2025' or later. \ No newline at end of file diff --git a/tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2022).js b/tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2022).js new file mode 100644 index 0000000000000..ff340598e187b --- /dev/null +++ b/tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2022).js @@ -0,0 +1,10 @@ +//// [tests/cases/conformance/es2025/regexPatternModifiersAndDuplicateNamedGroups.ts] //// + +//// [regexPatternModifiersAndDuplicateNamedGroups.ts] +const dupNames = /(?\d{4})-\d{2}|\d{2}\/(?\d{4})/; +const modifiers = /(?i:abc)/; + +//// [regexPatternModifiersAndDuplicateNamedGroups.js] +"use strict"; +const dupNames = /(?\d{4})-\d{2}|\d{2}\/(?\d{4})/; +const modifiers = /(?i:abc)/; diff --git a/tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2022).symbols b/tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2022).symbols new file mode 100644 index 0000000000000..5619566555fd1 --- /dev/null +++ b/tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2022).symbols @@ -0,0 +1,9 @@ +//// [tests/cases/conformance/es2025/regexPatternModifiersAndDuplicateNamedGroups.ts] //// + +=== regexPatternModifiersAndDuplicateNamedGroups.ts === +const dupNames = /(?\d{4})-\d{2}|\d{2}\/(?\d{4})/; +>dupNames : Symbol(dupNames, Decl(regexPatternModifiersAndDuplicateNamedGroups.ts, 0, 5)) + +const modifiers = /(?i:abc)/; +>modifiers : Symbol(modifiers, Decl(regexPatternModifiersAndDuplicateNamedGroups.ts, 1, 5)) + diff --git a/tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2022).types b/tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2022).types new file mode 100644 index 0000000000000..deb097c9cf803 --- /dev/null +++ b/tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2022).types @@ -0,0 +1,15 @@ +//// [tests/cases/conformance/es2025/regexPatternModifiersAndDuplicateNamedGroups.ts] //// + +=== regexPatternModifiersAndDuplicateNamedGroups.ts === +const dupNames = /(?\d{4})-\d{2}|\d{2}\/(?\d{4})/; +>dupNames : RegExp +> : ^^^^^^ +>/(?\d{4})-\d{2}|\d{2}\/(?\d{4})/ : RegExp +> : ^^^^^^ + +const modifiers = /(?i:abc)/; +>modifiers : RegExp +> : ^^^^^^ +>/(?i:abc)/ : RegExp +> : ^^^^^^ + diff --git a/tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2025).js b/tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2025).js new file mode 100644 index 0000000000000..ff340598e187b --- /dev/null +++ b/tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2025).js @@ -0,0 +1,10 @@ +//// [tests/cases/conformance/es2025/regexPatternModifiersAndDuplicateNamedGroups.ts] //// + +//// [regexPatternModifiersAndDuplicateNamedGroups.ts] +const dupNames = /(?\d{4})-\d{2}|\d{2}\/(?\d{4})/; +const modifiers = /(?i:abc)/; + +//// [regexPatternModifiersAndDuplicateNamedGroups.js] +"use strict"; +const dupNames = /(?\d{4})-\d{2}|\d{2}\/(?\d{4})/; +const modifiers = /(?i:abc)/; diff --git a/tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2025).symbols b/tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2025).symbols new file mode 100644 index 0000000000000..5619566555fd1 --- /dev/null +++ b/tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2025).symbols @@ -0,0 +1,9 @@ +//// [tests/cases/conformance/es2025/regexPatternModifiersAndDuplicateNamedGroups.ts] //// + +=== regexPatternModifiersAndDuplicateNamedGroups.ts === +const dupNames = /(?\d{4})-\d{2}|\d{2}\/(?\d{4})/; +>dupNames : Symbol(dupNames, Decl(regexPatternModifiersAndDuplicateNamedGroups.ts, 0, 5)) + +const modifiers = /(?i:abc)/; +>modifiers : Symbol(modifiers, Decl(regexPatternModifiersAndDuplicateNamedGroups.ts, 1, 5)) + diff --git a/tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2025).types b/tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2025).types new file mode 100644 index 0000000000000..deb097c9cf803 --- /dev/null +++ b/tests/baselines/reference/regexPatternModifiersAndDuplicateNamedGroups(target=es2025).types @@ -0,0 +1,15 @@ +//// [tests/cases/conformance/es2025/regexPatternModifiersAndDuplicateNamedGroups.ts] //// + +=== regexPatternModifiersAndDuplicateNamedGroups.ts === +const dupNames = /(?\d{4})-\d{2}|\d{2}\/(?\d{4})/; +>dupNames : RegExp +> : ^^^^^^ +>/(?\d{4})-\d{2}|\d{2}\/(?\d{4})/ : RegExp +> : ^^^^^^ + +const modifiers = /(?i:abc)/; +>modifiers : RegExp +> : ^^^^^^ +>/(?i:abc)/ : RegExp +> : ^^^^^^ + diff --git a/tests/baselines/reference/regularExpressionScanning(target=es2015).errors.txt b/tests/baselines/reference/regularExpressionScanning(target=es2015).errors.txt index a32fb1567c578..5c10d75fbeaa4 100644 --- a/tests/baselines/reference/regularExpressionScanning(target=es2015).errors.txt +++ b/tests/baselines/reference/regularExpressionScanning(target=es2015).errors.txt @@ -13,6 +13,7 @@ regularExpressionScanning.ts(3,19): error TS1499: Unknown regular expression fla regularExpressionScanning.ts(3,20): error TS1499: Unknown regular expression flag. regularExpressionScanning.ts(3,21): error TS1500: Duplicate regular expression flag. regularExpressionScanning.ts(3,22): error TS1499: Unknown regular expression flag. +regularExpressionScanning.ts(5,5): error TS18062: Regular expression pattern modifiers are only available when targeting 'es2025' or later. regularExpressionScanning.ts(5,6): error TS1499: Unknown regular expression flag. regularExpressionScanning.ts(5,7): error TS1509: This regular expression flag cannot be toggled within a subpattern. regularExpressionScanning.ts(5,10): error TS1509: This regular expression flag cannot be toggled within a subpattern. @@ -45,11 +46,14 @@ regularExpressionScanning.ts(14,5): error TS1503: Named capturing groups are onl regularExpressionScanning.ts(14,14): error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. regularExpressionScanning.ts(14,29): error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. regularExpressionScanning.ts(14,45): error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. +regularExpressionScanning.ts(14,46): error TS18063: Duplicate named capturing groups are only available when targeting 'es2025' or later. regularExpressionScanning.ts(14,57): error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. +regularExpressionScanning.ts(14,58): error TS18063: Duplicate named capturing groups are only available when targeting 'es2025' or later. regularExpressionScanning.ts(15,15): error TS1532: There is no capturing group named 'absent' in this regular expression. regularExpressionScanning.ts(15,24): error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. regularExpressionScanning.ts(15,36): error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. regularExpressionScanning.ts(15,45): error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. +regularExpressionScanning.ts(15,46): error TS18063: Duplicate named capturing groups are only available when targeting 'es2025' or later. regularExpressionScanning.ts(15,58): error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. regularExpressionScanning.ts(15,59): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other. regularExpressionScanning.ts(17,31): error TS1507: There is nothing available for repetition. @@ -219,7 +223,7 @@ regularExpressionScanning.ts(47,89): error TS1518: Anything that would possibly regularExpressionScanning.ts(47,101): error TS1501: This regular expression flag is only available when targeting 'es2024' or later. -==== regularExpressionScanning.ts (219 errors) ==== +==== regularExpressionScanning.ts (223 errors) ==== const regexes: RegExp[] = [ // Flags /foo/visualstudiocode, @@ -255,6 +259,8 @@ regularExpressionScanning.ts(47,101): error TS1501: This regular expression flag !!! error TS1499: Unknown regular expression flag. // Pattern modifiers /(?med-ium:bar)/, + ~~~~~~~ +!!! error TS18062: Regular expression pattern modifiers are only available when targeting 'es2025' or later. ~ !!! error TS1499: Unknown regular expression flag. ~ @@ -328,8 +334,12 @@ regularExpressionScanning.ts(47,101): error TS1501: This regular expression flag !!! error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. ~~~~~ !!! error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. + ~~~ +!!! error TS18063: Duplicate named capturing groups are only available when targeting 'es2025' or later. ~~~~~ !!! error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. + ~~~ +!!! error TS18063: Duplicate named capturing groups are only available when targeting 'es2025' or later. /(\k)\k(?foo)|(?)((?)|(bar(?bar)))/, ~~~~~~ !!! error TS1532: There is no capturing group named 'absent' in this regular expression. @@ -339,6 +349,8 @@ regularExpressionScanning.ts(47,101): error TS1501: This regular expression flag !!! error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. ~~~~~ !!! error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. + ~~~ +!!! error TS18063: Duplicate named capturing groups are only available when targeting 'es2025' or later. ~~~~~ !!! error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. ~~~ diff --git a/tests/baselines/reference/regularExpressionScanning(target=es5).errors.txt b/tests/baselines/reference/regularExpressionScanning(target=es5).errors.txt index 110137f434016..1351848bd3df1 100644 --- a/tests/baselines/reference/regularExpressionScanning(target=es5).errors.txt +++ b/tests/baselines/reference/regularExpressionScanning(target=es5).errors.txt @@ -14,6 +14,7 @@ regularExpressionScanning.ts(3,19): error TS1499: Unknown regular expression fla regularExpressionScanning.ts(3,20): error TS1499: Unknown regular expression flag. regularExpressionScanning.ts(3,21): error TS1500: Duplicate regular expression flag. regularExpressionScanning.ts(3,22): error TS1499: Unknown regular expression flag. +regularExpressionScanning.ts(5,5): error TS18062: Regular expression pattern modifiers are only available when targeting 'es2025' or later. regularExpressionScanning.ts(5,6): error TS1499: Unknown regular expression flag. regularExpressionScanning.ts(5,7): error TS1509: This regular expression flag cannot be toggled within a subpattern. regularExpressionScanning.ts(5,10): error TS1509: This regular expression flag cannot be toggled within a subpattern. @@ -47,11 +48,14 @@ regularExpressionScanning.ts(14,5): error TS1503: Named capturing groups are onl regularExpressionScanning.ts(14,14): error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. regularExpressionScanning.ts(14,29): error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. regularExpressionScanning.ts(14,45): error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. +regularExpressionScanning.ts(14,46): error TS18063: Duplicate named capturing groups are only available when targeting 'es2025' or later. regularExpressionScanning.ts(14,57): error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. +regularExpressionScanning.ts(14,58): error TS18063: Duplicate named capturing groups are only available when targeting 'es2025' or later. regularExpressionScanning.ts(15,15): error TS1532: There is no capturing group named 'absent' in this regular expression. regularExpressionScanning.ts(15,24): error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. regularExpressionScanning.ts(15,36): error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. regularExpressionScanning.ts(15,45): error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. +regularExpressionScanning.ts(15,46): error TS18063: Duplicate named capturing groups are only available when targeting 'es2025' or later. regularExpressionScanning.ts(15,58): error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. regularExpressionScanning.ts(15,59): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other. regularExpressionScanning.ts(17,31): error TS1507: There is nothing available for repetition. @@ -228,7 +232,7 @@ regularExpressionScanning.ts(47,101): error TS1501: This regular expression flag !!! error TS5107: Option 'target=ES5' is deprecated and will stop functioning in TypeScript 7.0. Specify compilerOption '"ignoreDeprecations": "6.0"' to silence this error. -==== regularExpressionScanning.ts (226 errors) ==== +==== regularExpressionScanning.ts (230 errors) ==== const regexes: RegExp[] = [ // Flags /foo/visualstudiocode, @@ -264,6 +268,8 @@ regularExpressionScanning.ts(47,101): error TS1501: This regular expression flag !!! error TS1499: Unknown regular expression flag. // Pattern modifiers /(?med-ium:bar)/, + ~~~~~~~ +!!! error TS18062: Regular expression pattern modifiers are only available when targeting 'es2025' or later. ~ !!! error TS1499: Unknown regular expression flag. ~ @@ -339,8 +345,12 @@ regularExpressionScanning.ts(47,101): error TS1501: This regular expression flag !!! error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. ~~~~~ !!! error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. + ~~~ +!!! error TS18063: Duplicate named capturing groups are only available when targeting 'es2025' or later. ~~~~~ !!! error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. + ~~~ +!!! error TS18063: Duplicate named capturing groups are only available when targeting 'es2025' or later. /(\k)\k(?foo)|(?)((?)|(bar(?bar)))/, ~~~~~~ !!! error TS1532: There is no capturing group named 'absent' in this regular expression. @@ -350,6 +360,8 @@ regularExpressionScanning.ts(47,101): error TS1501: This regular expression flag !!! error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. ~~~~~ !!! error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. + ~~~ +!!! error TS18063: Duplicate named capturing groups are only available when targeting 'es2025' or later. ~~~~~ !!! error TS1503: Named capturing groups are only available when targeting 'ES2018' or later. ~~~ diff --git a/tests/cases/conformance/es2025/regexPatternModifiersAndDuplicateNamedGroups.ts b/tests/cases/conformance/es2025/regexPatternModifiersAndDuplicateNamedGroups.ts new file mode 100644 index 0000000000000..bda78276e94d0 --- /dev/null +++ b/tests/cases/conformance/es2025/regexPatternModifiersAndDuplicateNamedGroups.ts @@ -0,0 +1,4 @@ +// @target: es2022,es2025 + +const dupNames = /(?\d{4})-\d{2}|\d{2}\/(?\d{4})/; +const modifiers = /(?i:abc)/; \ No newline at end of file