Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
6628267
Renaming `namedCaptureGroups` to `hasNamedCapturingGroups`
graphemecluster Nov 16, 2025
cf301f9
Fix Incorrect Disjunction Alternative Visibility
graphemecluster Nov 17, 2025
af9d18a
Add fast path to `utf16Length`
graphemecluster Nov 17, 2025
fc9cb97
Fix: `inEscape` should always be checked and toggled first
graphemecluster Nov 17, 2025
a1fd6fa
Fast path to "Numbers out of order" check
graphemecluster Nov 17, 2025
d217838
Correct error message for simultaneous `(?uv:)` in pattern modifiers
graphemecluster Nov 17, 2025
21a3a2b
Refactor: Replace `0x80` with `utf8.RuneSelf`
graphemecluster Nov 17, 2025
74a02b9
Add "Use LanguageFeatureMinimumTarget" TODO comments
graphemecluster Nov 17, 2025
5f13252
Add two comments
graphemecluster Nov 17, 2025
46e2000
Refactor(Fix Incorrect Disjunction): Don't return token value in `sca…
graphemecluster Nov 17, 2025
c4c7671
Refactor: extract digit parsing to separate methods
graphemecluster Nov 17, 2025
c4c1dbe
Refactor: Use `AppendSeq` for spelling candidates for consistency
graphemecluster Nov 17, 2025
528d7ba
Fix: Only word characters should be scanned in Unicode property value…
graphemecluster Nov 17, 2025
581edc1
Refactor: Use `switch` for `canonicalName`
graphemecluster Nov 17, 2025
bceabaf
Fix: `/[\c]/` should match `\` (Incorrect error text range in `/[_-\c…
graphemecluster Nov 17, 2025
87e01b0
Fix escape sequence error position (removes 1 diff)
graphemecluster Nov 17, 2025
63a819a
Refactor: Replace slices with `charAtOffset`
graphemecluster Nov 17, 2025
60a35ea
Remove redundant check
graphemecluster Nov 17, 2025
a2ffe1a
Remove a mistaken error in `scanClassSetExpression` (https://github.c…
graphemecluster Nov 17, 2025
fed5053
Clarify comments in `scanClassSetExpression`
graphemecluster Nov 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
247 changes: 137 additions & 110 deletions internal/regexpchecker/regexpchecker.go

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions internal/regexpchecker/tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -550,10 +550,10 @@ func isValidNonBinaryUnicodePropertyName(name string) bool {

func isValidUnicodeProperty(name, value string) bool {
canonicalName := nonBinaryUnicodePropertyNames[name]
if canonicalName == "General_Category" {
switch canonicalName {
case "General_Category":
return generalCategoryValues.Has(value)
}
if canonicalName == "Script" || canonicalName == "Script_Extensions" {
case "Script", "Script_Extensions":
return scriptValues.Has(value)
}
return false
Expand Down
14 changes: 11 additions & 3 deletions internal/regexpchecker/utf16.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,18 @@ func utf16Length(s string) int {
return 1
}

// Otherwise, count UTF-16 code units from UTF-8 runes
// Otherwise, count UTF-16 code units from UTF-8 string
sLength := len(s)
length := 0
for _, r := range s {
length += charSize(r)
// ASCII fast path similar to stdlib utf8.RuneCount
for ; length < sLength; length++ {
if ch := s[length]; ch == 0 || ch >= utf8.RuneSelf {
// non-ASCII slow path, count from runes
for _, r := range s[length:] {
length += charSize(r)
}
return length
}
}
return length
}
Expand Down
6 changes: 3 additions & 3 deletions internal/scanner/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -1401,7 +1401,7 @@ func (s *Scanner) scanIdentifier(prefixLength int) bool {
for {
s.pos++
ch = s.char()
if !(isWordCharacter(ch) || ch == '$') {
if !(IsWordCharacter(ch) || ch == '$') {
break
}
}
Expand Down Expand Up @@ -2007,7 +2007,7 @@ func IsValidIdentifier(s string) bool {
}

// Section 6.1.4
func isWordCharacter(ch rune) bool {
func IsWordCharacter(ch rune) bool {
return stringutil.IsASCIILetter(ch) || stringutil.IsDigit(ch) || ch == '_'
}

Expand All @@ -2020,7 +2020,7 @@ func IsIdentifierPart(ch rune) bool {
}

func IsIdentifierPartEx(ch rune, languageVariant core.LanguageVariant) bool {
return isWordCharacter(ch) || ch == '$' ||
return IsWordCharacter(ch) || ch == '$' ||
ch >= utf8.RuneSelf && isUnicodeIdentifierPart(ch) ||
languageVariant == core.LanguageVariantJSX && (ch == '-' || ch == ':') // "-" and ":" are valid in JSX Identifiers
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
regularExpressionDuplicateCapturingGroupName.ts(2,13): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
regularExpressionDuplicateCapturingGroupName.ts(3,14): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
regularExpressionDuplicateCapturingGroupName.ts(4,15): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
regularExpressionDuplicateCapturingGroupName.ts(5,16): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
regularExpressionDuplicateCapturingGroupName.ts(6,16): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
regularExpressionDuplicateCapturingGroupName.ts(7,18): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
regularExpressionDuplicateCapturingGroupName.ts(8,16): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
regularExpressionDuplicateCapturingGroupName.ts(9,18): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
regularExpressionDuplicateCapturingGroupName.ts(11,19): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
regularExpressionDuplicateCapturingGroupName.ts(12,21): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
regularExpressionDuplicateCapturingGroupName.ts(14,20): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
regularExpressionDuplicateCapturingGroupName.ts(15,20): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
regularExpressionDuplicateCapturingGroupName.ts(16,20): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
regularExpressionDuplicateCapturingGroupName.ts(19,12): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
regularExpressionDuplicateCapturingGroupName.ts(20,13): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
regularExpressionDuplicateCapturingGroupName.ts(23,50): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
regularExpressionDuplicateCapturingGroupName.ts(23,57): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
regularExpressionDuplicateCapturingGroupName.ts(23,64): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
regularExpressionDuplicateCapturingGroupName.ts(24,35): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
regularExpressionDuplicateCapturingGroupName.ts(24,42): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
regularExpressionDuplicateCapturingGroupName.ts(24,66): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
regularExpressionDuplicateCapturingGroupName.ts(24,74): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
regularExpressionDuplicateCapturingGroupName.ts(24,81): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
regularExpressionDuplicateCapturingGroupName.ts(24,89): error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.


==== regularExpressionDuplicateCapturingGroupName.ts (24 errors) ====
// Adjacent homonymous capturing groups
/(?<foo>)(?<foo>)/;
~~~
!!! error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
/(?<foo>)((?<foo>))/;
~~~
!!! error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
/((?<foo>))(?<foo>)/;
~~~
!!! error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
/((?<foo>))((?<foo>))/;
~~~
!!! error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
/(?<foo>)(?=(?<foo>))/;
~~~
!!! error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
/(?<=(?<foo>))(?<foo>)/;
~~~
!!! error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
/(?<foo>)(?!(?<foo>))/;
~~~
!!! error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
/(?<!(?<foo>))(?<foo>)/;
~~~
!!! error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.

/((?<foo>))((?=(?<foo>)))/;
~~~
!!! error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
/((?<!(?<foo>)))((?<foo>))/;
~~~
!!! error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.

/(?=(?<foo>))(?=(?<foo>))/;
~~~
!!! error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
/(?!(?<foo>))(?!(?<foo>))/;
~~~
!!! error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
/(?=(?<foo>))(?!(?<foo>))/;
~~~
!!! error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.

// Nested homonymous capturing groups
/(?<foo>(?<foo>))/;
~~~
!!! error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
/(?<foo>((?<foo>)))/;
~~~
!!! error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.

// Complicated cases
/(?<a>)((?<b>)((?<c>)|(?<d>))|(?<b>)|((?<c>)))(?<c>)((?<b>)|(?<d>))/;
~
!!! error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
~
!!! error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
~
!!! error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
/(?<a>)(((?<b>)|(?<c>))((?<d>)|(?<a>)|(?<b>))|(?<c>)|((?<d>)))(?<a>)(((?<b>)|(?<c>))|(?<d>))/;
~
!!! error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
~
!!! error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
~
!!! error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
~
!!! error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
~
!!! error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.
~
!!! error TS1515: Named capturing groups with the same name must be mutually exclusive to each other.

// Should not error
/(?<foo>)|(?<foo>)/;
/(?<foo>)|((?<foo>))/;
/((?<foo>))|(?<foo>)/;
/((?<foo>))|((?<foo>))/;

Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//// [tests/cases/compiler/regularExpressionDuplicateCapturingGroupName.ts] ////

//// [regularExpressionDuplicateCapturingGroupName.ts]
// Adjacent homonymous capturing groups
/(?<foo>)(?<foo>)/;
/(?<foo>)((?<foo>))/;
/((?<foo>))(?<foo>)/;
/((?<foo>))((?<foo>))/;
/(?<foo>)(?=(?<foo>))/;
/(?<=(?<foo>))(?<foo>)/;
/(?<foo>)(?!(?<foo>))/;
/(?<!(?<foo>))(?<foo>)/;

/((?<foo>))((?=(?<foo>)))/;
/((?<!(?<foo>)))((?<foo>))/;

/(?=(?<foo>))(?=(?<foo>))/;
/(?!(?<foo>))(?!(?<foo>))/;
/(?=(?<foo>))(?!(?<foo>))/;

// Nested homonymous capturing groups
/(?<foo>(?<foo>))/;
/(?<foo>((?<foo>)))/;

// Complicated cases
/(?<a>)((?<b>)((?<c>)|(?<d>))|(?<b>)|((?<c>)))(?<c>)((?<b>)|(?<d>))/;
/(?<a>)(((?<b>)|(?<c>))((?<d>)|(?<a>)|(?<b>))|(?<c>)|((?<d>)))(?<a>)(((?<b>)|(?<c>))|(?<d>))/;

// Should not error
/(?<foo>)|(?<foo>)/;
/(?<foo>)|((?<foo>))/;
/((?<foo>))|(?<foo>)/;
/((?<foo>))|((?<foo>))/;


//// [regularExpressionDuplicateCapturingGroupName.js]
// Adjacent homonymous capturing groups
/(?<foo>)(?<foo>)/;
/(?<foo>)((?<foo>))/;
/((?<foo>))(?<foo>)/;
/((?<foo>))((?<foo>))/;
/(?<foo>)(?=(?<foo>))/;
/(?<=(?<foo>))(?<foo>)/;
/(?<foo>)(?!(?<foo>))/;
/(?<!(?<foo>))(?<foo>)/;
/((?<foo>))((?=(?<foo>)))/;
/((?<!(?<foo>)))((?<foo>))/;
/(?=(?<foo>))(?=(?<foo>))/;
/(?!(?<foo>))(?!(?<foo>))/;
/(?=(?<foo>))(?!(?<foo>))/;
// Nested homonymous capturing groups
/(?<foo>(?<foo>))/;
/(?<foo>((?<foo>)))/;
// Complicated cases
/(?<a>)((?<b>)((?<c>)|(?<d>))|(?<b>)|((?<c>)))(?<c>)((?<b>)|(?<d>))/;
/(?<a>)(((?<b>)|(?<c>))((?<d>)|(?<a>)|(?<b>))|(?<c>)|((?<d>)))(?<a>)(((?<b>)|(?<c>))|(?<d>))/;
// Should not error
/(?<foo>)|(?<foo>)/;
/(?<foo>)|((?<foo>))/;
/((?<foo>))|(?<foo>)/;
/((?<foo>))|((?<foo>))/;
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//// [tests/cases/compiler/regularExpressionDuplicateCapturingGroupName.ts] ////

=== regularExpressionDuplicateCapturingGroupName.ts ===

// Adjacent homonymous capturing groups
/(?<foo>)(?<foo>)/;
/(?<foo>)((?<foo>))/;
/((?<foo>))(?<foo>)/;
/((?<foo>))((?<foo>))/;
/(?<foo>)(?=(?<foo>))/;
/(?<=(?<foo>))(?<foo>)/;
/(?<foo>)(?!(?<foo>))/;
/(?<!(?<foo>))(?<foo>)/;

/((?<foo>))((?=(?<foo>)))/;
/((?<!(?<foo>)))((?<foo>))/;

/(?=(?<foo>))(?=(?<foo>))/;
/(?!(?<foo>))(?!(?<foo>))/;
/(?=(?<foo>))(?!(?<foo>))/;

// Nested homonymous capturing groups
/(?<foo>(?<foo>))/;
/(?<foo>((?<foo>)))/;

// Complicated cases
/(?<a>)((?<b>)((?<c>)|(?<d>))|(?<b>)|((?<c>)))(?<c>)((?<b>)|(?<d>))/;
/(?<a>)(((?<b>)|(?<c>))((?<d>)|(?<a>)|(?<b>))|(?<c>)|((?<d>)))(?<a>)(((?<b>)|(?<c>))|(?<d>))/;

// Should not error
/(?<foo>)|(?<foo>)/;
/(?<foo>)|((?<foo>))/;
/((?<foo>))|(?<foo>)/;
/((?<foo>))|((?<foo>))/;

Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//// [tests/cases/compiler/regularExpressionDuplicateCapturingGroupName.ts] ////

=== regularExpressionDuplicateCapturingGroupName.ts ===
// Adjacent homonymous capturing groups
/(?<foo>)(?<foo>)/;
>/(?<foo>)(?<foo>)/ : RegExp

/(?<foo>)((?<foo>))/;
>/(?<foo>)((?<foo>))/ : RegExp

/((?<foo>))(?<foo>)/;
>/((?<foo>))(?<foo>)/ : RegExp

/((?<foo>))((?<foo>))/;
>/((?<foo>))((?<foo>))/ : RegExp

/(?<foo>)(?=(?<foo>))/;
>/(?<foo>)(?=(?<foo>))/ : RegExp

/(?<=(?<foo>))(?<foo>)/;
>/(?<=(?<foo>))(?<foo>)/ : RegExp

/(?<foo>)(?!(?<foo>))/;
>/(?<foo>)(?!(?<foo>))/ : RegExp

/(?<!(?<foo>))(?<foo>)/;
>/(?<!(?<foo>))(?<foo>)/ : RegExp

/((?<foo>))((?=(?<foo>)))/;
>/((?<foo>))((?=(?<foo>)))/ : RegExp

/((?<!(?<foo>)))((?<foo>))/;
>/((?<!(?<foo>)))((?<foo>))/ : RegExp

/(?=(?<foo>))(?=(?<foo>))/;
>/(?=(?<foo>))(?=(?<foo>))/ : RegExp

/(?!(?<foo>))(?!(?<foo>))/;
>/(?!(?<foo>))(?!(?<foo>))/ : RegExp

/(?=(?<foo>))(?!(?<foo>))/;
>/(?=(?<foo>))(?!(?<foo>))/ : RegExp

// Nested homonymous capturing groups
/(?<foo>(?<foo>))/;
>/(?<foo>(?<foo>))/ : RegExp

/(?<foo>((?<foo>)))/;
>/(?<foo>((?<foo>)))/ : RegExp

// Complicated cases
/(?<a>)((?<b>)((?<c>)|(?<d>))|(?<b>)|((?<c>)))(?<c>)((?<b>)|(?<d>))/;
>/(?<a>)((?<b>)((?<c>)|(?<d>))|(?<b>)|((?<c>)))(?<c>)((?<b>)|(?<d>))/ : RegExp

/(?<a>)(((?<b>)|(?<c>))((?<d>)|(?<a>)|(?<b>))|(?<c>)|((?<d>)))(?<a>)(((?<b>)|(?<c>))|(?<d>))/;
>/(?<a>)(((?<b>)|(?<c>))((?<d>)|(?<a>)|(?<b>))|(?<c>)|((?<d>)))(?<a>)(((?<b>)|(?<c>))|(?<d>))/ : RegExp

// Should not error
/(?<foo>)|(?<foo>)/;
>/(?<foo>)|(?<foo>)/ : RegExp

/(?<foo>)|((?<foo>))/;
>/(?<foo>)|((?<foo>))/ : RegExp

/((?<foo>))|(?<foo>)/;
>/((?<foo>))|(?<foo>)/ : RegExp

/((?<foo>))|((?<foo>))/;
>/((?<foo>))|((?<foo>))/ : RegExp

Loading