re2 1.18.3 → 1.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -58,6 +58,7 @@ Supported properties:
58
58
  * [`re2.unicode`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/unicode)
59
59
  * `RE2` engine always works in the Unicode mode. See details below.
60
60
  * [`re2.sticky`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/sticky)
61
+ * *Since 1.19.0*: [`re2.hasIndices`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/hasIndices)
61
62
  * [`re2.source`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/source)
62
63
  * [`re2.flags`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/flags)
63
64
 
@@ -352,6 +353,7 @@ console.log('re2_res : ' + re2_res); // prints: re2_res : abc,a,b,c
352
353
 
353
354
  ## Release history
354
355
 
356
+ - 1.19.0 *Added `hasIndices` AKA the `d` flag. Thx, [teebu](https://github.com/teebu).*
355
357
  - 1.18.3 *Fixed bug with non-matched groups. Thx, [Dan Setterquist](https://github.com/dset).*
356
358
  - 1.18.2 *Reference to the binary module by its full name.*
357
359
  - 1.18.1 *Support for Node 16, 18, 20 + Darwin arm64 precompiled binaries.*
package/lib/exec.cc CHANGED
@@ -159,7 +159,19 @@ NAN_METHOD(WrappedRE2::Exec)
159
159
  Nan::Set(result, Nan::New("groups").ToLocalChecked(), groups);
160
160
 
161
161
  if (re2->hasIndices) {
162
- Nan::Set(indices, Nan::New("groups").ToLocalChecked(), groups);
162
+ auto indexGroups = Nan::New<v8::Object>();
163
+ Nan::SetPrototype(indexGroups, Nan::Null());
164
+
165
+ for (auto group : groupNames)
166
+ {
167
+ auto value = Nan::Get(indices, group.first);
168
+ if (!value.IsEmpty())
169
+ {
170
+ Nan::Set(indexGroups, Nan::New(group.second).ToLocalChecked(), value.ToLocalChecked());
171
+ }
172
+ }
173
+
174
+ Nan::Set(indices, Nan::New("groups").ToLocalChecked(), indexGroups);
163
175
  }
164
176
  }
165
177
  else
package/lib/match.cc CHANGED
@@ -82,7 +82,7 @@ NAN_METHOD(WrappedRE2::Match)
82
82
 
83
83
  // form a result
84
84
 
85
- auto result = Nan::New<v8::Array>();
85
+ auto result = Nan::New<v8::Array>(), indices = Nan::New<v8::Array>();
86
86
 
87
87
  if (a.isBuffer)
88
88
  {
@@ -93,6 +93,23 @@ NAN_METHOD(WrappedRE2::Match)
93
93
  if (data)
94
94
  {
95
95
  Nan::Set(result, i, Nan::CopyBuffer(data, item.size()).ToLocalChecked());
96
+ if (!re2->global && re2->hasIndices)
97
+ {
98
+ auto pair = Nan::New<v8::Array>();
99
+ auto offset = getUtf16Length(a.data + lastIndex, data);
100
+ auto length = getUtf16Length(data, data + item.size());
101
+ Nan::Set(pair, 0, Nan::New<v8::Integer>(static_cast<int>(offset)));
102
+ Nan::Set(pair, 1, Nan::New<v8::Integer>(static_cast<int>(offset + length)));
103
+ Nan::Set(indices, i, pair);
104
+ }
105
+ }
106
+ else
107
+ {
108
+ Nan::Set(result, i, Nan::Undefined());
109
+ if (!re2->global && re2->hasIndices)
110
+ {
111
+ Nan::Set(indices, i, Nan::Undefined());
112
+ }
96
113
  }
97
114
  }
98
115
  if (!re2->global)
@@ -110,6 +127,23 @@ NAN_METHOD(WrappedRE2::Match)
110
127
  if (data)
111
128
  {
112
129
  Nan::Set(result, i, Nan::New(data, item.size()).ToLocalChecked());
130
+ if (!re2->global && re2->hasIndices)
131
+ {
132
+ auto pair = Nan::New<v8::Array>();
133
+ auto offset = getUtf16Length(a.data + lastIndex, data);
134
+ auto length = getUtf16Length(data, data + item.size());
135
+ Nan::Set(pair, 0, Nan::New<v8::Integer>(static_cast<int>(offset)));
136
+ Nan::Set(pair, 1, Nan::New<v8::Integer>(static_cast<int>(offset + length)));
137
+ Nan::Set(indices, i, pair);
138
+ }
139
+ }
140
+ else
141
+ {
142
+ Nan::Set(result, i, Nan::Undefined());
143
+ if (!re2->global && re2->hasIndices)
144
+ {
145
+ Nan::Set(indices, i, Nan::Undefined());
146
+ }
113
147
  }
114
148
  }
115
149
  if (!re2->global)
@@ -146,12 +180,38 @@ NAN_METHOD(WrappedRE2::Match)
146
180
  }
147
181
 
148
182
  Nan::Set(result, Nan::New("groups").ToLocalChecked(), groups);
183
+
184
+ if (re2->hasIndices)
185
+ {
186
+ auto indexGroups = Nan::New<v8::Object>();
187
+ Nan::SetPrototype(indexGroups, Nan::Null());
188
+
189
+ for (auto group : groupNames)
190
+ {
191
+ auto value = Nan::Get(indices, group.first);
192
+ if (!value.IsEmpty())
193
+ {
194
+ Nan::Set(indexGroups, Nan::New(group.second).ToLocalChecked(), value.ToLocalChecked());
195
+ }
196
+ }
197
+
198
+ Nan::Set(indices, Nan::New("groups").ToLocalChecked(), indexGroups);
199
+ }
149
200
  }
150
201
  else
151
202
  {
152
203
  Nan::Set(result, Nan::New("groups").ToLocalChecked(), Nan::Undefined());
204
+ if (re2->hasIndices)
205
+ {
206
+ Nan::Set(indices, Nan::New("groups").ToLocalChecked(), Nan::Undefined());
207
+ }
153
208
  }
154
209
  }
155
210
 
211
+ if (re2->hasIndices)
212
+ {
213
+ Nan::Set(result, Nan::New("indices").ToLocalChecked(), indices);
214
+ }
215
+
156
216
  info.GetReturnValue().Set(result);
157
217
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "re2",
3
- "version": "1.18.3",
3
+ "version": "1.19.0",
4
4
  "description": "Bindings for RE2: fast, safe alternative to backtracking regular expression engines.",
5
5
  "homepage": "https://github.com/uhop/node-re2",
6
6
  "bugs": "https://github.com/uhop/node-re2/issues",
@@ -21,9 +21,13 @@ unit.add(module, [
21
21
 
22
22
  var result = re.exec('The Quick Brown Fox Jumps Over The Lazy Dog');
23
23
 
24
- eval(t.TEST("t.unify(result, ['Quick Brown Fox Jumps', 'Brown', 'Jumps'])"));
24
+ eval(
25
+ t.TEST("t.unify(result, ['Quick Brown Fox Jumps', 'Brown', 'Jumps'])")
26
+ );
25
27
  eval(t.TEST('result.index === 4'));
26
- eval(t.TEST("result.input === 'The Quick Brown Fox Jumps Over The Lazy Dog'"));
28
+ eval(
29
+ t.TEST("result.input === 'The Quick Brown Fox Jumps Over The Lazy Dog'")
30
+ );
27
31
  eval(t.TEST('re.lastIndex === 25'));
28
32
  },
29
33
  function test_execSucc(t) {
@@ -148,12 +152,20 @@ unit.add(module, [
148
152
 
149
153
  var result = re.exec('Каждый Охотник Желает Знать Где Сидит Фазан');
150
154
 
151
- eval(t.TEST("t.unify(result, ['Охотник Желает Знать Где', 'Желает', 'Где'])"));
155
+ eval(
156
+ t.TEST("t.unify(result, ['Охотник Желает Знать Где', 'Желает', 'Где'])")
157
+ );
152
158
  eval(t.TEST('result.index === 7'));
153
- eval(t.TEST("result.input === 'Каждый Охотник Желает Знать Где Сидит Фазан'"));
159
+ eval(
160
+ t.TEST("result.input === 'Каждый Охотник Желает Знать Где Сидит Фазан'")
161
+ );
154
162
  eval(t.TEST('re.lastIndex === 31'));
155
163
 
156
- eval(t.TEST("result.input.substr(result.index) === 'Охотник Желает Знать Где Сидит Фазан'"));
164
+ eval(
165
+ t.TEST(
166
+ "result.input.substr(result.index) === 'Охотник Желает Знать Где Сидит Фазан'"
167
+ )
168
+ );
157
169
  eval(t.TEST("result.input.substr(re.lastIndex) === ' Сидит Фазан'"));
158
170
  },
159
171
  function test_execUnicodeSubsequent(t) {
@@ -248,11 +260,21 @@ unit.add(module, [
248
260
 
249
261
  eval(t.TEST('result.index === 13'));
250
262
  eval(t.TEST('result.input instanceof Buffer'));
251
- eval(t.TEST("result.input.toString() === 'Каждый Охотник Желает Знать Где Сидит Фазан'"));
263
+ eval(
264
+ t.TEST(
265
+ "result.input.toString() === 'Каждый Охотник Желает Знать Где Сидит Фазан'"
266
+ )
267
+ );
252
268
  eval(t.TEST('re.lastIndex === 58'));
253
269
 
254
- eval(t.TEST("result.input.toString('utf8', result.index) === 'Охотник Желает Знать Где Сидит Фазан'"));
255
- eval(t.TEST("result.input.toString('utf8', re.lastIndex) === ' Сидит Фазан'"));
270
+ eval(
271
+ t.TEST(
272
+ "result.input.toString('utf8', result.index) === 'Охотник Желает Знать Где Сидит Фазан'"
273
+ )
274
+ );
275
+ eval(
276
+ t.TEST("result.input.toString('utf8', re.lastIndex) === ' Сидит Фазан'")
277
+ );
256
278
  },
257
279
 
258
280
  // Sticky tests
@@ -317,7 +339,9 @@ xy2 (at start of line)
317
339
  eval(t.TEST("result[0] === 'xy'"));
318
340
  eval(t.TEST('result.index > 3'));
319
341
  eval(t.TEST('result.index < pattern.length - 4'));
320
- eval(t.TEST('result[0] === pattern.substr(result.index, result[0].length)'));
342
+ eval(
343
+ t.TEST('result[0] === pattern.substr(result.index, result[0].length)')
344
+ );
321
345
  },
322
346
 
323
347
  // dotAll tests
@@ -332,5 +356,63 @@ xy2 (at start of line)
332
356
  eval(t.TEST("new RE2('a.c', 's').test('abc')"));
333
357
  eval(t.TEST("new RE2(/a.c/s).test('a c')"));
334
358
  eval(t.TEST("new RE2(/a.c/s).test('a\\nc')"));
359
+ },
360
+
361
+ // hasIndices tests
362
+
363
+ function test_execHasIndices(t) {
364
+ 'use strict';
365
+
366
+ eval(t.TEST("!new RE2('1').hasIndices"));
367
+ eval(t.TEST('!new RE2(/1/).hasIndices'));
368
+
369
+ var re = new RE2('(aa)(?<b>b)?(?<c>ccc)', 'd');
370
+
371
+ eval(t.TEST('re.hasIndices'));
372
+
373
+ var result = re.exec('1aabccc2');
374
+
375
+ eval(t.TEST('result.length === 4'));
376
+ eval(t.TEST("result.input === '1aabccc2'"));
377
+ eval(t.TEST('result.index === 1'));
378
+ eval(t.TEST('Object.keys(result.groups).length === 2'));
379
+ eval(t.TEST("result.groups.b === 'b'"));
380
+ eval(t.TEST("result.groups.c === 'ccc'"));
381
+ eval(t.TEST("result[0] === 'aabccc'"));
382
+ eval(t.TEST("result[1] === 'aa'"));
383
+ eval(t.TEST("result[2] === 'b'"));
384
+ eval(t.TEST("result[3] === 'ccc'"));
385
+ eval(t.TEST('result.indices.length === 4'));
386
+ eval(t.TEST('t.unify(result.indices, [[1, 7], [1, 3], [3, 4], [4, 7]])'));
387
+ eval(t.TEST('Object.keys(result.indices.groups).length === 2'));
388
+ eval(t.TEST('t.unify(result.indices.groups.b, [3, 4])'));
389
+ eval(t.TEST('t.unify(result.indices.groups.c, [4, 7])'));
390
+
391
+ result = re.exec('1aaccc2');
392
+
393
+ eval(t.TEST('result.length === 4'));
394
+ eval(t.TEST("result.input === '1aaccc2'"));
395
+ eval(t.TEST('result.index === 1'));
396
+ eval(t.TEST('Object.keys(result.groups).length === 2'));
397
+ eval(t.TEST('result.groups.b === undefined'));
398
+ eval(t.TEST("result.groups.c === 'ccc'"));
399
+ eval(t.TEST("result[0] === 'aaccc'"));
400
+ eval(t.TEST("result[1] === 'aa'"));
401
+ eval(t.TEST('result[2] === undefined'));
402
+ eval(t.TEST("result[3] === 'ccc'"));
403
+ eval(t.TEST('result.indices.length === 4'));
404
+ eval(
405
+ t.TEST('t.unify(result.indices, [[1, 6], [1, 3], undefined, [3, 6]])')
406
+ );
407
+ eval(t.TEST('Object.keys(result.indices.groups).length === 2'));
408
+ eval(t.TEST('t.unify(result.indices.groups.b, undefined)'));
409
+ eval(t.TEST('t.unify(result.indices.groups.c, [3, 6])'));
410
+
411
+ try {
412
+ re = new RE2(new RegExp('1', 'd'));
413
+ eval(t.TEST('re.hasIndices'));
414
+ } catch (e) {
415
+ // squelch
416
+ }
335
417
  }
336
418
  ]);
@@ -1,137 +1,161 @@
1
- "use strict";
2
-
3
-
4
- var unit = require("heya-unit");
5
- var RE2 = require("../re2");
1
+ 'use strict';
6
2
 
3
+ var unit = require('heya-unit');
4
+ var RE2 = require('../re2');
7
5
 
8
6
  // tests
9
7
 
10
8
  unit.add(module, [
9
+ // These tests are copied from MDN:
10
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match
11
+
12
+ function test_match(t) {
13
+ 'use strict';
14
+
15
+ var str = 'For more information, see Chapter 3.4.5.1';
16
+
17
+ var re = new RE2(/(chapter \d+(\.\d)*)/i);
18
+ var result = re.match(str);
19
+
20
+ eval(t.TEST('result.input === str'));
21
+ eval(t.TEST('result.index === 26'));
22
+ eval(t.TEST('result.length === 3'));
23
+ eval(t.TEST("result[0] === 'Chapter 3.4.5.1'"));
24
+ eval(t.TEST("result[1] === 'Chapter 3.4.5.1'"));
25
+ eval(t.TEST("result[2] === '.1'"));
26
+ },
27
+ function test_matchGlobal(t) {
28
+ 'use strict';
11
29
 
12
- // These tests are copied from MDN:
13
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match
14
-
15
- function test_match(t) {
16
- "use strict";
30
+ var re = new RE2(/[A-E]/gi);
31
+ var result = re.match(
32
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
33
+ );
17
34
 
18
- var str = "For more information, see Chapter 3.4.5.1";
35
+ eval(
36
+ t.TEST(
37
+ "t.unify(result, ['A', 'B', 'C', 'D', 'E', 'a', 'b', 'c', 'd', 'e'])"
38
+ )
39
+ );
40
+ },
41
+ function test_matchFail(t) {
42
+ 'use strict';
19
43
 
20
- var re = new RE2(/(chapter \d+(\.\d)*)/i);
21
- var result = re.match(str);
44
+ var re = new RE2('(a+)?(b+)?');
45
+ var result = re.match('aaabb');
22
46
 
23
- eval(t.TEST("result.input === str"));
24
- eval(t.TEST("result.index === 26"));
25
- eval(t.TEST("result.length === 3"));
26
- eval(t.TEST("result[0] === 'Chapter 3.4.5.1'"));
27
- eval(t.TEST("result[1] === 'Chapter 3.4.5.1'"));
28
- eval(t.TEST("result[2] === '.1'"));
29
- },
30
- function test_matchGlobal(t) {
31
- "use strict";
47
+ eval(t.TEST("result[1] === 'aaa'"));
48
+ eval(t.TEST("result[2] === 'bb'"));
32
49
 
33
- var re = new RE2(/[A-E]/gi);
34
- var result = re.match("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
50
+ result = re.match('aaacbb');
35
51
 
36
- eval(t.TEST("t.unify(result, ['A', 'B', 'C', 'D', 'E', 'a', 'b', 'c', 'd', 'e'])"));
37
- },
38
- function test_matchFail(t) {
39
- "use strict";
52
+ eval(t.TEST("result[1] === 'aaa'"));
53
+ eval(t.TEST('result[2] === undefined'));
54
+ },
55
+ function test_matchInvalid(t) {
56
+ 'use strict';
40
57
 
41
- var re = new RE2("(a+)?(b+)?");
42
- var result = re.match("aaabb");
58
+ var re = RE2('');
43
59
 
44
- eval(t.TEST("result[1] === 'aaa'"));
45
- eval(t.TEST("result[2] === 'bb'"));
60
+ try {
61
+ re.match({
62
+ toString() {
63
+ throw 'corner';
64
+ }
65
+ });
66
+ t.test(false); // shouldn't be here
67
+ } catch (e) {
68
+ eval(t.TEST("e === 'corner'"));
69
+ }
70
+ },
46
71
 
47
- result = re.match("aaacbb");
72
+ // Unicode tests
48
73
 
49
- eval(t.TEST("result[1] === 'aaa'"));
50
- eval(t.TEST("result[2] === undefined"));
51
- },
52
- function test_matchInvalid(t) {
53
- "use strict";
74
+ function test_matchUnicode(t) {
75
+ 'use strict';
54
76
 
55
- var re = RE2('');
77
+ var str = 'Это ГЛАВА 3.4.5.1';
56
78
 
57
- try {
58
- re.match({ toString() { throw "corner"; } });
59
- t.test(false); // shouldn't be here
60
- } catch(e) {
61
- eval(t.TEST("e === 'corner'"));
62
- }
63
- },
79
+ var re = new RE2(/(глава \d+(\.\d)*)/i);
80
+ var result = re.match(str);
64
81
 
65
- // Unicode tests
82
+ eval(t.TEST('result.input === str'));
83
+ eval(t.TEST('result.index === 4'));
84
+ eval(t.TEST('result.length === 3'));
85
+ eval(t.TEST("result[0] === 'ГЛАВА 3.4.5.1'"));
86
+ eval(t.TEST("result[1] === 'ГЛАВА 3.4.5.1'"));
87
+ eval(t.TEST("result[2] === '.1'"));
88
+ },
66
89
 
67
- function test_matchUnicode(t) {
68
- "use strict";
90
+ // Buffer tests
69
91
 
70
- var str = "Это ГЛАВА 3.4.5.1";
92
+ function test_matchBuffer(t) {
93
+ 'use strict';
71
94
 
72
- var re = new RE2(/(глава \d+(\.\d)*)/i);
73
- var result = re.match(str);
95
+ var buf = new Buffer('Это ГЛАВА 3.4.5.1');
74
96
 
75
- eval(t.TEST("result.input === str"));
76
- eval(t.TEST("result.index === 4"));
77
- eval(t.TEST("result.length === 3"));
78
- eval(t.TEST("result[0] === 'ГЛАВА 3.4.5.1'"));
79
- eval(t.TEST("result[1] === 'ГЛАВА 3.4.5.1'"));
80
- eval(t.TEST("result[2] === '.1'"));
81
- },
97
+ var re = new RE2(/(глава \d+(\.\d)*)/i);
98
+ var result = re.match(buf);
82
99
 
83
- // Buffer tests
100
+ eval(t.TEST('result.input instanceof Buffer'));
101
+ eval(t.TEST('result.length === 3'));
102
+ eval(t.TEST('result[0] instanceof Buffer'));
103
+ eval(t.TEST('result[1] instanceof Buffer'));
104
+ eval(t.TEST('result[2] instanceof Buffer'));
84
105
 
85
- function test_matchBuffer(t) {
86
- "use strict";
106
+ eval(t.TEST('result.input === buf'));
107
+ eval(t.TEST('result.index === 7'));
108
+ eval(
109
+ t.TEST("result.input.toString('utf8', result.index) === 'ГЛАВА 3.4.5.1'")
110
+ );
111
+ eval(t.TEST("result[0].toString() === 'ГЛАВА 3.4.5.1'"));
112
+ eval(t.TEST("result[1].toString() === 'ГЛАВА 3.4.5.1'"));
113
+ eval(t.TEST("result[2].toString() === '.1'"));
114
+ },
87
115
 
88
- var buf = new Buffer("Это ГЛАВА 3.4.5.1");
116
+ // Sticky tests
89
117
 
90
- var re = new RE2(/(глава \d+(\.\d)*)/i);
91
- var result = re.match(buf);
118
+ function test_matchSticky(t) {
119
+ 'use strict';
92
120
 
93
- eval(t.TEST("result.input instanceof Buffer"));
94
- eval(t.TEST("result.length === 3"));
95
- eval(t.TEST("result[0] instanceof Buffer"));
96
- eval(t.TEST("result[1] instanceof Buffer"));
97
- eval(t.TEST("result[2] instanceof Buffer"));
121
+ var re = new RE2('\\s+', 'y');
98
122
 
99
- eval(t.TEST("result.input === buf"));
100
- eval(t.TEST("result.index === 7"));
101
- eval(t.TEST("result.input.toString('utf8', result.index) === 'ГЛАВА 3.4.5.1'"));
102
- eval(t.TEST("result[0].toString() === 'ГЛАВА 3.4.5.1'"));
103
- eval(t.TEST("result[1].toString() === 'ГЛАВА 3.4.5.1'"));
104
- eval(t.TEST("result[2].toString() === '.1'"));
105
- },
123
+ eval(t.TEST("re.match('Hello world, how are you?') === null"));
106
124
 
107
- // Sticky tests
125
+ re.lastIndex = 5;
108
126
 
109
- function test_matchSticky(t) {
110
- "use strict";
127
+ var result = re.match('Hello world, how are you?');
111
128
 
112
- var re = new RE2("\\s+", "y");
129
+ eval(t.TEST("t.unify(result, [' '])"));
130
+ eval(t.TEST('result.index === 5'));
131
+ eval(t.TEST('re.lastIndex === 6'));
113
132
 
114
- eval(t.TEST("re.match('Hello world, how are you?') === null"));
133
+ var re2 = new RE2('\\s+', 'gy');
115
134
 
116
- re.lastIndex = 5;
135
+ eval(t.TEST("re2.match('Hello world, how are you?') === null"));
117
136
 
118
- var result = re.match("Hello world, how are you?");
137
+ re2.lastIndex = 5;
119
138
 
120
- eval(t.TEST("t.unify(result, [' '])"));
121
- eval(t.TEST("result.index === 5"));
122
- eval(t.TEST("re.lastIndex === 6"));
139
+ eval(t.TEST("re2.match('Hello world, how are you?') === null"));
123
140
 
124
- var re2 = new RE2("\\s+", "gy");
141
+ var re3 = new RE2(/[A-E]/giy);
142
+ var result3 = re3.match(
143
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
144
+ );
125
145
 
126
- eval(t.TEST("re2.match('Hello world, how are you?') === null"));
146
+ eval(t.TEST("t.unify(result3, ['A', 'B', 'C', 'D', 'E'])"));
147
+ },
127
148
 
128
- re2.lastIndex = 5;
149
+ // hasIndices tests
129
150
 
130
- eval(t.TEST("re2.match('Hello world, how are you?') === null"));
151
+ function test_matchHasIndices(t) {
152
+ 'use strict';
131
153
 
132
- var re3 = new RE2(/[A-E]/giy);
133
- var result3 = re3.match("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
154
+ var re = new RE2('(aa)(?<b>b)?(?<c>ccc)', 'd'),
155
+ str1 = '1aabccc2',
156
+ str2 = '1aaccc2';
134
157
 
135
- eval(t.TEST("t.unify(result3, ['A', 'B', 'C', 'D', 'E'])"));
136
- }
158
+ eval(t.TEST("t.unify(str1.match(re), re.exec(str1))"));
159
+ eval(t.TEST("t.unify(str2.match(re), re.exec(str2))"));
160
+ }
137
161
  ]);
@@ -13,7 +13,10 @@ unit.add(module, [
13
13
  'use strict';
14
14
 
15
15
  var re = new RE2(/apples/gi);
16
- var result = re.replace('Apples are round, and apples are juicy.', 'oranges');
16
+ var result = re.replace(
17
+ 'Apples are round, and apples are juicy.',
18
+ 'oranges'
19
+ );
17
20
  eval(t.TEST("result === 'oranges are round, and oranges are juicy.'"));
18
21
 
19
22
  re = new RE2(/xmas/i);
@@ -199,15 +202,24 @@ unit.add(module, [
199
202
  'use strict';
200
203
 
201
204
  var re = new RE2(/яблоки/gi);
202
- var result = re.replace(new Buffer('Яблоки красны, яблоки сочны.'), 'апельсины');
205
+ var result = re.replace(
206
+ new Buffer('Яблоки красны, яблоки сочны.'),
207
+ 'апельсины'
208
+ );
203
209
  eval(t.TEST('result instanceof Buffer'));
204
210
  eval(t.TEST("result.toString() === 'апельсины красны, апельсины сочны.'"));
205
211
 
206
- result = re.replace(new Buffer('Яблоки красны, яблоки сочны.'), new Buffer('апельсины'));
212
+ result = re.replace(
213
+ new Buffer('Яблоки красны, яблоки сочны.'),
214
+ new Buffer('апельсины')
215
+ );
207
216
  eval(t.TEST('result instanceof Buffer'));
208
217
  eval(t.TEST("result.toString() === 'апельсины красны, апельсины сочны.'"));
209
218
 
210
- result = re.replace('Яблоки красны, яблоки сочны.', new Buffer('апельсины'));
219
+ result = re.replace(
220
+ 'Яблоки красны, яблоки сочны.',
221
+ new Buffer('апельсины')
222
+ );
211
223
  eval(t.TEST("typeof result == 'string'"));
212
224
  eval(t.TEST("result === 'апельсины красны, апельсины сочны.'"));
213
225
  },
@@ -284,7 +296,7 @@ unit.add(module, [
284
296
 
285
297
  // Non-matches
286
298
 
287
- function test_ReplaceOneNonMatch(t) {
299
+ function test_replaceOneNonMatch(t) {
288
300
  'use strict';
289
301
 
290
302
  function replacer(match, capture, offset, string) {
@@ -300,10 +312,10 @@ unit.add(module, [
300
312
  var re = new RE2(/hello (world)?/);
301
313
  re.replace('hello ', replacer);
302
314
  },
303
- function test_ReplaceTwoNonMatches(t) {
315
+ function test_replaceTwoNonMatches(t) {
304
316
  'use strict';
305
317
 
306
- function replacer(match, capture1, capture2, offset, string) {
318
+ function replacer(match, capture1, capture2, offset, string, groups) {
307
319
  t.test(typeof offset == 'number');
308
320
  t.test(typeof match == 'string');
309
321
  t.test(typeof string == 'string');
@@ -312,10 +324,14 @@ unit.add(module, [
312
324
  t.test(offset === 1);
313
325
  t.test(match === 'b & y');
314
326
  t.test(string === 'ab & yz');
327
+ t.test(typeof groups == 'object');
328
+ t.test(Object.keys(groups).length == 2);
329
+ t.test(groups.a === undefined);
330
+ t.test(groups.b == undefined);
315
331
  return '';
316
332
  }
317
333
 
318
- var re = new RE2(/b(1)? & (2)?y/);
334
+ var re = new RE2(/b(?<a>1)? & (?<b>2)?y/);
319
335
  var result = re.replace('ab & yz', replacer);
320
336
  eval(t.TEST("result === 'az'"));
321
337
  }