Skip to content

Commit 523fc8b

Browse files
elitvyakovljharb
authored andcommitted
es5-shim: fix groups with quantifiers preventing its exercise
1 parent f0dd919 commit 523fc8b

File tree

2 files changed

+109
-7
lines changed

2 files changed

+109
-7
lines changed

es5-shim.js

Lines changed: 80 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1925,20 +1925,93 @@
19251925
}());
19261926

19271927
if (!replaceReportsGroupsCorrectly) {
1928+
/**
1929+
* @param regexp {RegExp}
1930+
* @returns {Object[]} groups
1931+
* @return {number} groups[].number - The number of group.
1932+
* @return {boolean} groups[].mayBeMissing - The group with quantifiers preventing its exercise, the matched text
1933+
* for a capturing group is now undefined instead of an empty string.
1934+
* The group without quantifiers, may be empty string.
1935+
* @return {boolean} groups[].isResulting - The groups with ?:, ?=, ?! are non-capturing groups.
1936+
*/
1937+
var getExtendedGroups = function getExtendedGroups(regexp) {
1938+
var source = regexp.source;
1939+
var result = [];
1940+
var groupNumberCounter = 0;
1941+
1942+
for (var charIndex in source) {
1943+
var char = source[+charIndex];
1944+
var prevFirst = source[+charIndex - 1] || null;
1945+
var nextFirst = source[+charIndex + 1] || null;
1946+
var nextSecond = source[+charIndex + 2] || null;
1947+
1948+
if (char === '(') {
1949+
if (prevFirst && prevFirst === '\\') {
1950+
continue;
1951+
}
1952+
1953+
if (
1954+
nextFirst && nextFirst === '?' && nextSecond && nextSecond === ':'
1955+
|| nextFirst && nextFirst === '?' && nextSecond && nextSecond === '='
1956+
|| nextFirst && nextFirst === '?' && nextSecond && nextSecond === '!'
1957+
) {
1958+
groupNumberCounter += 1;
1959+
result.push({
1960+
number: groupNumberCounter,
1961+
mayBeMissing: true,
1962+
isResulting: false
1963+
});
1964+
continue;
1965+
}
1966+
1967+
result.push({
1968+
number: ++groupNumberCounter,
1969+
mayBeMissing: false,
1970+
isResulting: true
1971+
});
1972+
}
1973+
1974+
if (char === ')') {
1975+
var groupIndex = groupNumberCounter - 1;
1976+
1977+
if (prevFirst && prevFirst === '\\') {
1978+
continue;
1979+
}
1980+
1981+
if (result[groupIndex] && !result[groupIndex].isResulting) {
1982+
array_splice.apply(result,[groupIndex, 1]);
1983+
groupNumberCounter = --groupNumberCounter;
1984+
continue;
1985+
}
1986+
1987+
if (nextFirst && (nextFirst === '?' || nextFirst === '*')) {
1988+
result[groupIndex].mayBeMissing = true;
1989+
}
1990+
}
1991+
}
1992+
1993+
return result;
1994+
};
1995+
19281996
StringPrototype.replace = function replace(searchValue, replaceValue) {
19291997
var isFn = isCallable(replaceValue);
19301998
var hasCapturingGroups = isRegex(searchValue) && (/\)[*?]/).test(searchValue.source);
1999+
var extendedGroups = getExtendedGroups(searchValue);
2000+
19312001
if (!isFn || !hasCapturingGroups) {
19322002
return str_replace.call(this, searchValue, replaceValue);
19332003
} else {
19342004
var wrappedReplaceValue = function (match) {
1935-
var length = arguments.length;
1936-
var originalLastIndex = searchValue.lastIndex;
1937-
searchValue.lastIndex = 0; // eslint-disable-line no-param-reassign
1938-
var args = searchValue.exec(match) || [];
1939-
searchValue.lastIndex = originalLastIndex; // eslint-disable-line no-param-reassign
1940-
pushCall(args, arguments[length - 2], arguments[length - 1]);
1941-
return replaceValue.apply(this, args);
2005+
var groups = arraySlice(arguments, 1, -2);
2006+
2007+
for (var i = 0; i < groups.length; i++) {
2008+
var argumentIndex = i + 1;
2009+
if (groups[i] === '' && extendedGroups[i].mayBeMissing) {
2010+
arguments[argumentIndex] = undefined;
2011+
}
2012+
}
2013+
2014+
return apply.call(replaceValue, this, arguments);
19422015
};
19432016
return str_replace.call(this, searchValue, wrappedReplaceValue);
19442017
}

tests/spec/s-string.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,35 @@ describe('String', function () {
3333
);
3434
}).not.toThrow();
3535
});
36+
37+
it('should be 10 arguments in Firefox prior 34 version', function () {
38+
var size = null;
39+
40+
'* alef\n* beth \n* gimel~0\n'.replace(
41+
/(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+([^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm,
42+
function (match, m1, m2, m3, m4) {
43+
size = arguments.length;
44+
}
45+
);
46+
47+
expect(size).toBe(10);
48+
});
49+
50+
it('first group have to be undefined and second have to be empty string', function () {
51+
var firstGroup,
52+
secondGroup;
53+
54+
'x'.replace(
55+
/x(.)?(.*)/gm,
56+
function (match, m1, m2) {
57+
firstGroup = m1;
58+
secondGroup = m2;
59+
}
60+
);
61+
62+
expect(firstGroup).toBe(undefined);
63+
expect(secondGroup).toBe('');
64+
});
3665
});
3766

3867
describe('#split()', function () {

0 commit comments

Comments
 (0)