re2 1.18.3 → 1.19.1

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,8 @@ console.log('re2_res : ' + re2_res); // prints: re2_res : abc,a,b,c
352
353
 
353
354
  ## Release history
354
355
 
356
+ - 1.19.1 *Bugfix: indices for the `d` flag when `lastIndex` is non zero. Bugfix: the match result. Thx, [teebu](https://github.com/teebu).*
357
+ - 1.19.0 *Added `hasIndices` AKA the `d` flag. Thx, [teebu](https://github.com/teebu).*
355
358
  - 1.18.3 *Fixed bug with non-matched groups. Thx, [Dan Setterquist](https://github.com/dset).*
356
359
  - 1.18.2 *Reference to the binary module by its full name.*
357
360
  - 1.18.1 *Support for Node 16, 18, 20 + Darwin arm64 precompiled binaries.*
package/lib/exec.cc CHANGED
@@ -90,8 +90,8 @@ NAN_METHOD(WrappedRE2::Exec)
90
90
  if (re2->hasIndices) {
91
91
  auto pair = Nan::New<v8::Array>();
92
92
  auto offset = data - str.data;
93
- Nan::Set(pair, 0, Nan::New<v8::Integer>(static_cast<int>(offset)));
94
- Nan::Set(pair, 1, Nan::New<v8::Integer>(static_cast<int>(offset + item.size())));
93
+ Nan::Set(pair, 0, Nan::New<v8::Integer>(indexOffset + static_cast<int>(offset)));
94
+ Nan::Set(pair, 1, Nan::New<v8::Integer>(indexOffset + static_cast<int>(offset + item.size())));
95
95
  Nan::Set(indices, i, pair);
96
96
  }
97
97
  }
@@ -118,8 +118,8 @@ NAN_METHOD(WrappedRE2::Exec)
118
118
  auto pair = Nan::New<v8::Array>();
119
119
  auto offset = getUtf16Length(str.data + lastIndex, data);
120
120
  auto length = getUtf16Length(data, data + item.size());
121
- Nan::Set(pair, 0, Nan::New<v8::Integer>(static_cast<int>(offset)));
122
- Nan::Set(pair, 1, Nan::New<v8::Integer>(static_cast<int>(offset + length)));
121
+ Nan::Set(pair, 0, Nan::New<v8::Integer>(indexOffset + static_cast<int>(offset)));
122
+ Nan::Set(pair, 1, Nan::New<v8::Integer>(indexOffset + static_cast<int>(offset + length)));
123
123
  Nan::Set(indices, i, pair);
124
124
  }
125
125
  }
@@ -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,10 +180,35 @@ 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
+ }
208
+ }
209
+ if (re2->hasIndices)
210
+ {
211
+ Nan::Set(result, Nan::New("indices").ToLocalChecked(), indices);
153
212
  }
154
213
  }
155
214
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "re2",
3
- "version": "1.18.3",
3
+ "version": "1.19.1",
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",
@@ -13,12 +13,12 @@
13
13
  "dependencies": {
14
14
  "install-artifact-from-github": "^1.3.3",
15
15
  "nan": "^2.17.0",
16
- "node-gyp": "^9.3.1"
16
+ "node-gyp": "^9.4.0"
17
17
  },
18
18
  "devDependencies": {
19
- "@types/node": "^20.2.3",
19
+ "@types/node": "^20.3.1",
20
20
  "heya-unit": "^0.3.0",
21
- "typescript": "^5.0.4"
21
+ "typescript": "^5.1.3"
22
22
  },
23
23
  "scripts": {
24
24
  "test": "node tests/tests.js",
@@ -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,85 @@ 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
+ }
417
+ },
418
+
419
+ function test_hasIndexLastIndex(t) {
420
+ 'use strict';
421
+
422
+ const re2 = new RE2('a', 'dg');
423
+
424
+ eval(t.TEST('re2.lastIndex === 0'));
425
+
426
+ let result = re2.exec('abca');
427
+ eval(t.TEST('re2.lastIndex === 1'));
428
+ eval(t.TEST('result.index === 0'));
429
+ eval(t.TEST('t.unify(result.indices, [[0, 1]])'));
430
+
431
+ result = re2.exec('abca');
432
+ eval(t.TEST('re2.lastIndex === 4'));
433
+ eval(t.TEST('result.index === 3'));
434
+ eval(t.TEST('t.unify(result.indices, [[3, 4]])'));
435
+
436
+ result = re2.exec('abca');
437
+ eval(t.TEST('re2.lastIndex === 0'));
438
+ eval(t.TEST('result === null'));
335
439
  }
336
440
  ]);
@@ -1,137 +1,172 @@
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';
29
+
30
+ var re = new RE2(/[A-E]/gi);
31
+ var result = re.match(
32
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
33
+ );
34
+
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';
11
43
 
12
- // These tests are copied from MDN:
13
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match
44
+ var re = new RE2('(a+)?(b+)?');
45
+ var result = re.match('aaabb');
14
46
 
15
- function test_match(t) {
16
- "use strict";
47
+ eval(t.TEST("result[1] === 'aaa'"));
48
+ eval(t.TEST("result[2] === 'bb'"));
17
49
 
18
- var str = "For more information, see Chapter 3.4.5.1";
50
+ result = re.match('aaacbb');
19
51
 
20
- var re = new RE2(/(chapter \d+(\.\d)*)/i);
21
- var result = re.match(str);
52
+ eval(t.TEST("result[1] === 'aaa'"));
53
+ eval(t.TEST('result[2] === undefined'));
54
+ },
55
+ function test_matchInvalid(t) {
56
+ 'use strict';
22
57
 
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";
58
+ var re = RE2('');
32
59
 
33
- var re = new RE2(/[A-E]/gi);
34
- var result = re.match("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
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
+ },
35
71
 
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";
72
+ // Unicode tests
40
73
 
41
- var re = new RE2("(a+)?(b+)?");
42
- var result = re.match("aaabb");
74
+ function test_matchUnicode(t) {
75
+ 'use strict';
43
76
 
44
- eval(t.TEST("result[1] === 'aaa'"));
45
- eval(t.TEST("result[2] === 'bb'"));
77
+ var str = 'Это ГЛАВА 3.4.5.1';
46
78
 
47
- result = re.match("aaacbb");
79
+ var re = new RE2(/(глава \d+(\.\d)*)/i);
80
+ var result = re.match(str);
48
81
 
49
- eval(t.TEST("result[1] === 'aaa'"));
50
- eval(t.TEST("result[2] === undefined"));
51
- },
52
- function test_matchInvalid(t) {
53
- "use strict";
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
+ },
54
89
 
55
- var re = RE2('');
90
+ // Buffer tests
56
91
 
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
- },
92
+ function test_matchBuffer(t) {
93
+ 'use strict';
64
94
 
65
- // Unicode tests
95
+ var buf = new Buffer('Это ГЛАВА 3.4.5.1');
66
96
 
67
- function test_matchUnicode(t) {
68
- "use strict";
97
+ var re = new RE2(/(глава \d+(\.\d)*)/i);
98
+ var result = re.match(buf);
69
99
 
70
- var str = "Это ГЛАВА 3.4.5.1";
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'));
71
105
 
72
- var re = new RE2(/(глава \d+(\.\d)*)/i);
73
- var result = re.match(str);
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
+ },
74
115
 
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
- },
116
+ // Sticky tests
82
117
 
83
- // Buffer tests
118
+ function test_matchSticky(t) {
119
+ 'use strict';
84
120
 
85
- function test_matchBuffer(t) {
86
- "use strict";
121
+ var re = new RE2('\\s+', 'y');
87
122
 
88
- var buf = new Buffer("Это ГЛАВА 3.4.5.1");
123
+ eval(t.TEST("re.match('Hello world, how are you?') === null"));
89
124
 
90
- var re = new RE2(/(глава \d+(\.\d)*)/i);
91
- var result = re.match(buf);
125
+ re.lastIndex = 5;
92
126
 
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"));
127
+ var result = re.match('Hello world, how are you?');
98
128
 
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
- },
129
+ eval(t.TEST("t.unify(result, [' '])"));
130
+ eval(t.TEST('result.index === 5'));
131
+ eval(t.TEST('re.lastIndex === 6'));
106
132
 
107
- // Sticky tests
133
+ var re2 = new RE2('\\s+', 'gy');
108
134
 
109
- function test_matchSticky(t) {
110
- "use strict";
135
+ eval(t.TEST("re2.match('Hello world, how are you?') === null"));
111
136
 
112
- var re = new RE2("\\s+", "y");
137
+ re2.lastIndex = 5;
113
138
 
114
- eval(t.TEST("re.match('Hello world, how are you?') === null"));
139
+ eval(t.TEST("re2.match('Hello world, how are you?') === null"));
115
140
 
116
- re.lastIndex = 5;
141
+ var re3 = new RE2(/[A-E]/giy);
142
+ var result3 = re3.match(
143
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
144
+ );
117
145
 
118
- var result = re.match("Hello world, how are you?");
146
+ eval(t.TEST("t.unify(result3, ['A', 'B', 'C', 'D', 'E'])"));
147
+ },
119
148
 
120
- eval(t.TEST("t.unify(result, [' '])"));
121
- eval(t.TEST("result.index === 5"));
122
- eval(t.TEST("re.lastIndex === 6"));
149
+ // hasIndices tests
123
150
 
124
- var re2 = new RE2("\\s+", "gy");
151
+ function test_matchHasIndices(t) {
152
+ 'use strict';
125
153
 
126
- eval(t.TEST("re2.match('Hello world, how are you?') === null"));
154
+ const re = new RE2('(aa)(?<b>b)?(?<c>ccc)', 'd'),
155
+ str1 = '1aabccc2',
156
+ str2 = '1aaccc2';
127
157
 
128
- re2.lastIndex = 5;
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
+ },
129
161
 
130
- eval(t.TEST("re2.match('Hello world, how are you?') === null"));
162
+ function test_matchHasIndicesGlobal(t) {
163
+ 'use strict';
131
164
 
132
- var re3 = new RE2(/[A-E]/giy);
133
- var result3 = re3.match("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
165
+ const re = new RE2('(?<zzz>a)', 'dg'),
166
+ result = 'abca'.match(re);
134
167
 
135
- eval(t.TEST("t.unify(result3, ['A', 'B', 'C', 'D', 'E'])"));
136
- }
168
+ eval(t.TEST("t.unify(result, ['a', 'a'])"));
169
+ eval(t.TEST("!('indices' in result)"));
170
+ eval(t.TEST("!('groups' in result)"));
171
+ }
137
172
  ]);
@@ -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
  }