@@ -2,17 +2,20 @@ var DESCRIPTORS = require('../internals/descriptors');
2
2
var global = require ( '../internals/global' ) ;
3
3
var isForced = require ( '../internals/is-forced' ) ;
4
4
var inheritIfRequired = require ( '../internals/inherit-if-required' ) ;
5
+ var createNonEnumerableProperty = require ( '../internals/create-non-enumerable-property' ) ;
5
6
var defineProperty = require ( '../internals/object-define-property' ) . f ;
6
7
var getOwnPropertyNames = require ( '../internals/object-get-own-property-names' ) . f ;
7
8
var isRegExp = require ( '../internals/is-regexp' ) ;
8
9
var getFlags = require ( '../internals/regexp-flags' ) ;
9
10
var stickyHelpers = require ( '../internals/regexp-sticky-helpers' ) ;
10
11
var redefine = require ( '../internals/redefine' ) ;
11
12
var fails = require ( '../internals/fails' ) ;
13
+ var has = require ( '../internals/has' ) ;
12
14
var enforceInternalState = require ( '../internals/internal-state' ) . enforce ;
13
15
var setSpecies = require ( '../internals/set-species' ) ;
14
16
var wellKnownSymbol = require ( '../internals/well-known-symbol' ) ;
15
17
var UNSUPPORTED_DOT_ALL = require ( '../internals/regexp-unsupported-dot-all' ) ;
18
+ var UNSUPPORTED_NCG = require ( '../internals/regexp-unsupported-ncg' ) ;
16
19
17
20
var MATCH = wellKnownSymbol ( 'match' ) ;
18
21
var NativeRegExp = global . RegExp ;
@@ -25,16 +28,17 @@ var CORRECT_NEW = new NativeRegExp(re1) !== re1;
25
28
26
29
var UNSUPPORTED_Y = stickyHelpers . UNSUPPORTED_Y ;
27
30
28
- var BASE_FORCED = DESCRIPTORS && ! CORRECT_NEW || UNSUPPORTED_Y || UNSUPPORTED_DOT_ALL || fails ( function ( ) {
29
- re2 [ MATCH ] = false ;
30
- // RegExp constructor can alter flags and IsRegExp works correct with @@match
31
- return NativeRegExp ( re1 ) != re1 || NativeRegExp ( re2 ) == re2 || NativeRegExp ( re1 , 'i' ) != '/a/i' ;
32
- } ) ;
31
+ var BASE_FORCED = DESCRIPTORS &&
32
+ ( ! CORRECT_NEW || UNSUPPORTED_Y || UNSUPPORTED_DOT_ALL || UNSUPPORTED_NCG || fails ( function ( ) {
33
+ re2 [ MATCH ] = false ;
34
+ // RegExp constructor can alter flags and IsRegExp works correct with @@match
35
+ return NativeRegExp ( re1 ) != re1 || NativeRegExp ( re2 ) == re2 || NativeRegExp ( re1 , 'i' ) != '/a/i' ;
36
+ } ) ) ;
33
37
34
- var deDotAll = function ( string ) {
35
- var result = '' ;
36
- var index = 0 ;
38
+ var handleDotAll = function ( string ) {
37
39
var length = string . length ;
40
+ var index = 0 ;
41
+ var result = '' ;
38
42
var brackets = false ;
39
43
var chr ;
40
44
for ( ; index <= length ; index ++ ) {
@@ -55,14 +59,60 @@ var deDotAll = function (string) {
55
59
} return result ;
56
60
} ;
57
61
62
+ var handleNCG = function ( string ) {
63
+ var length = string . length ;
64
+ var index = 0 ;
65
+ var result = '' ;
66
+ var named = [ ] ;
67
+ var names = { } ;
68
+ var brackets = false ;
69
+ var ncg = false ;
70
+ var groupid = 0 ;
71
+ var groupname = '' ;
72
+ var chr ;
73
+ for ( ; index <= length ; index ++ ) {
74
+ chr = string . charAt ( index ) ;
75
+ if ( chr === '\\' ) {
76
+ chr = chr + string . charAt ( ++ index ) ;
77
+ } else if ( chr === ']' ) {
78
+ brackets = false ;
79
+ } else if ( ! brackets ) switch ( true ) {
80
+ case chr === '[' :
81
+ brackets = true ;
82
+ break ;
83
+ case chr === '(' :
84
+ // TODO: Use only propper RegExpIdentifierName
85
+ if ( / \? < [ ^ ! # % & * + = @ ^ ] / . test ( string . slice ( index + 1 , index + 4 ) ) ) {
86
+ index += 2 ;
87
+ ncg = true ;
88
+ }
89
+ result += chr ;
90
+ groupid ++ ;
91
+ continue ;
92
+ case chr === '>' && ncg :
93
+ if ( groupname === '' || has ( names , groupname ) ) {
94
+ throw new TypeError ( 'Invalid capture group name' ) ;
95
+ }
96
+ names [ groupname ] = true ;
97
+ named . push ( [ groupname , groupid ] ) ;
98
+ ncg = false ;
99
+ groupname = '' ;
100
+ continue ;
101
+ }
102
+ if ( ncg ) groupname += chr ;
103
+ else result += chr ;
104
+ } return [ result , named ] ;
105
+ } ;
106
+
58
107
// `RegExp` constructor
59
108
// https://tc39.es/ecma262/#sec-regexp-constructor
60
109
if ( isForced ( 'RegExp' , BASE_FORCED ) ) {
61
110
var RegExpWrapper = function RegExp ( pattern , flags ) {
62
111
var thisIsRegExp = this instanceof RegExpWrapper ;
63
112
var patternIsRegExp = isRegExp ( pattern ) ;
64
113
var flagsAreUndefined = flags === undefined ;
65
- var rawFlags , dotAll , sticky , result , state ;
114
+ var groups = [ ] ;
115
+ var rawPattern , rawFlags , dotAll , sticky , handled , result , state ;
66
116
67
117
if ( ! thisIsRegExp && patternIsRegExp && pattern . constructor === RegExpWrapper && flagsAreUndefined ) {
68
118
return pattern ;
@@ -75,6 +125,10 @@ if (isForced('RegExp', BASE_FORCED)) {
75
125
pattern = pattern . source ;
76
126
}
77
127
128
+ pattern = pattern === undefined ? '' : String ( pattern ) ;
129
+ if ( pattern === '' ) pattern = '(?:)' ;
130
+ rawPattern = pattern ;
131
+
78
132
if ( UNSUPPORTED_DOT_ALL ) {
79
133
dotAll = ! ! flags && flags . indexOf ( 's' ) > - 1 ;
80
134
if ( dotAll ) flags = flags . replace ( / s / g, '' ) ;
@@ -87,21 +141,33 @@ if (isForced('RegExp', BASE_FORCED)) {
87
141
if ( sticky ) flags = flags . replace ( / y / g, '' ) ;
88
142
}
89
143
144
+ if ( UNSUPPORTED_NCG ) {
145
+ handled = handleNCG ( pattern ) ;
146
+ pattern = handled [ 0 ] ;
147
+ groups = handled [ 1 ] ;
148
+ }
149
+
90
150
result = inheritIfRequired (
91
151
CORRECT_NEW ? new NativeRegExp ( pattern , flags ) : NativeRegExp ( pattern , flags ) ,
92
152
thisIsRegExp ? this : RegExpPrototype ,
93
153
RegExpWrapper
94
154
) ;
95
155
96
- if ( dotAll || sticky ) {
156
+ if ( dotAll || sticky || groups . length ) {
97
157
state = enforceInternalState ( result ) ;
98
158
if ( dotAll ) {
99
159
state . dotAll = true ;
100
- state . raw = RegExpWrapper ( deDotAll ( pattern ) , rawFlags ) ;
160
+ state . raw = RegExpWrapper ( handleDotAll ( pattern ) , rawFlags ) ;
101
161
}
102
162
if ( sticky ) state . sticky = true ;
163
+ if ( groups . length ) state . groups = groups ;
103
164
}
104
165
166
+ if ( pattern !== rawPattern ) try {
167
+ // fails in old engines, but we have no alternatives for unsupported regex syntax
168
+ createNonEnumerableProperty ( result , 'source' , rawPattern ) ;
169
+ } catch ( error ) { /* empty */ }
170
+
105
171
return result ;
106
172
} ;
107
173
0 commit comments