diff --git a/packages/core-js/modules/es.regexp.constructor.js b/packages/core-js/modules/es.regexp.constructor.js index a12a5a3e0291..b9e5ca1b8a0b 100644 --- a/packages/core-js/modules/es.regexp.constructor.js +++ b/packages/core-js/modules/es.regexp.constructor.js @@ -95,11 +95,13 @@ var handleNCG = function (string) { brackets = true; break; case chr === '(': - if (exec(IS_NCG, stringSlice(string, index + 1))) { + result += chr; + if (stringSlice(string, index + 1, index + 3) === '?:') { // avoid groupid increment in non-capturing group + continue; + } else if (exec(IS_NCG, stringSlice(string, index + 1))) { index += 2; ncg = true; } - result += chr; groupid++; continue; case chr === '>' && ncg: diff --git a/tests/unit-global/es.regexp.constructor.js b/tests/unit-global/es.regexp.constructor.js index 9a376d1dafc7..d22e0ce562f6 100644 --- a/tests/unit-global/es.regexp.constructor.js +++ b/tests/unit-global/es.regexp.constructor.js @@ -84,6 +84,15 @@ if (DESCRIPTORS) { const { groups } = RegExp('foo:(?\\w+),bar:(?\\w+)').exec('foo:abc,bar:def'); assert.same(getPrototypeOf(groups), null, 'null prototype'); assert.deepEqual(groups, { foo: 'abc', bar: 'def' }, 'NCG #3'); + // eslint-disable-next-line regexp/no-useless-non-capturing-group -- required for testing + const { groups: nonCaptured, length } = RegExp('foo:(?:value=(?\\w+)),bar:(?:value=(?\\w+))').exec('foo:value=abc,bar:value=def'); + assert.deepEqual(nonCaptured, { foo: 'abc', bar: 'def' }, 'NCG #4'); + assert.same(length, 3, 'incorrect number of matched entries #1'); + + // eslint-disable-next-line regexp/no-unused-capturing-group -- required for testing + const { groups: skipBar } = RegExp('foo:(?\\w+),bar:(\\w+),buz:(?\\w+)').exec('foo:abc,bar:def,buz:ghi'); + assert.deepEqual(skipBar, { foo: 'abc', buz: 'ghi' }, 'NCG #5'); + // fails in Safari // assert.same(Object.getPrototypeOf(groups), null, 'NCG #4'); assert.same('foo:abc,bar:def'.replace(RegExp('foo:(?\\w+),bar:(?\\w+)'), '$,$'), 'def,abc', 'replace #1');