Gate ES2025 regex syntax behind target - #4877
Conversation
Pattern modifiers and duplicate named capturing groups are parsed and validated by the scanner but never checked against target, so they compile clean at every target even though both are a SyntaxError on engines that predate ES2025. Report them below ES2025, matching how the v flag and named capturing groups are already gated. Fixes microsoft/TypeScript#63682
There was a problem hiding this comment.
Pull request overview
Adds ES2025 target checks for regular-expression pattern modifiers and duplicate named capture groups.
Changes:
- Adds scanner target diagnostics.
- Registers diagnostic codes TS18062 and TS18063.
- Adds compiler tests and baselines for ES2022 and ES2025.
Reviewed changes
Copilot reviewed 11 out of 12 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
internal/scanner/regexp.go |
Implements target checks. |
internal/diagnostics/extraDiagnosticMessages.json |
Defines new diagnostics. |
internal/diagnostics/diagnostics_generated.go |
Adds generated diagnostic mappings. |
testdata/tests/cases/compiler/regularExpressionES2025Syntax.ts |
Adds target-dependent tests. |
testdata/baselines/reference/compiler/regularExpressionES2025Syntax(target=es2022).errors.txt |
Records pre-ES2025 errors. |
testdata/baselines/reference/compiler/regularExpressionES2025Syntax(target=es2022).symbols |
Records ES2022 symbols. |
testdata/baselines/reference/compiler/regularExpressionES2025Syntax(target=es2022).types |
Records ES2022 types. |
testdata/baselines/reference/compiler/regularExpressionES2025Syntax(target=es2025).errors.txt |
Records ES2025 errors. |
testdata/baselines/reference/compiler/regularExpressionES2025Syntax(target=es2025).symbols |
Records ES2025 symbols. |
testdata/baselines/reference/compiler/regularExpressionES2025Syntax(target=es2025).types |
Records ES2025 types. |
testdata/baselines/reference/submodule/compiler/regularExpressionScanning(target=es2015).errors.txt |
Updates submodule baseline. |
testdata/baselines/reference/submodule/compiler/regularExpressionScanning(target=es2015).errors.txt.diff |
Records upstream divergence. |
Files not reviewed (1)
- internal/diagnostics/diagnostics_generated.go: Generated file
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
| // The name is not in scope for any enclosing alternative, so a previous definition of it | ||
| // can only have come from a mutually exclusive alternative. | ||
| if p.groupSpecifiers[p.scanner.tokenValue] && p.scanner.languageVersion() < core.ScriptTargetES2025 { | ||
| p.error(diagnostics.Duplicate_named_capturing_groups_are_only_available_when_targeting_0_or_later, p.scanner.tokenStart, p.pos()-p.scanner.tokenStart, strings.ToLower(core.ScriptTargetES2025.String())) |
There was a problem hiding this comment.
Confirmed, but I would rather fix it separately.
The missing TS1515 predates this change. scanDisjunction drops an alternative's scope once the alternative ends, in Strada too (topNamedCapturingGroupsScope = namedCapturingGroupsScopeStack.pop()), so the check is never reached for that pattern:
- tsc 5.9.3 on
/(?:(?<a>x)|y)(?<a>z)/: no error. It does report TS1515 for/(?<a>x)(?<a>y)/, so the rule itself works. - typescript@7.0.2 without this patch: no error.
What this PR does add is the wrong message for that pattern below ES2025: TS18063 where TS1515 belongs. It is still reported as an error, so nothing valid starts or stops compiling, but the wording points at the wrong cause.
Fixing the scope tracking means 7.x reports an error 6.0 does not, which is the same divergence question as in the description, so it seems better as its own PR with its own test matrix. Happy to open that once this lands.
|
@microsoft-github-policy-service agree |
Fixes microsoft/TypeScript#63682
Analysis
Pattern modifiers and duplicate named capturing groups are parsed and validated, but never checked against
target:Both are a
SyntaxErrorbefore ES2025. Thevflag and named capturing groups already have version gates. These two were Stage 3 with no edition assigned when regex body validation was written, so they never got one.Fix
Two checks in
internal/scanner/regexp.go:scanDisjunctionwhen the group actually consumed modifier characters. Comparing againstflagsStartkeeps plain(?:out.scanGroupNamewhen the name is already ingroupSpecifiersbut not in scope for any enclosing alternative. Duplicates inside one alternative still report only TS1515.New messages go in
extraDiagnosticMessages.jsonsince the submodule's json is not editable here. 18062 and 18063 are unused upstream.Test:
regularExpressionES2025Syntax.tsat es2022 and es2025, including the cases that must stay clean ((?:, non-duplicated names).One thing to flag: this creates a 6.0/7.0 difference instead of removing one. Upstream's
regularExpressionScanning.tsat es2015 gains 4 errors, so this adds a.diffbaseline. 6.0 is closed, so the gate can only land on 7.x. Happy to close it if you would rather keep the gap.Copilot Checklist
I successfully ran these commands at the end of my session, and they completed without error:
Lint fails only in
internal/nativepath/realpath_darwin_test.go, which is identical tomainon this branch../internal/scanner/...and./internal/diagnostics/...report 0 issues.Disclosure: written with AI assistance (Claude Code). I read the change and will handle review myself.