Skip to content

Commit

Permalink
[Breaking] throw on non-global/nullish flags
Browse files Browse the repository at this point in the history
  • Loading branch information
ljharb committed Oct 3, 2019
1 parent b670a3b commit c1717e6
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 21 deletions.
8 changes: 2 additions & 6 deletions README.md
Expand Up @@ -36,9 +36,7 @@ assert.deepEqual([...matchAll(str, globalRegex)], [
Object.assign(['c'], { index: 3, input: str, groups: undefined }),
]);

assert.deepEqual([...matchAll(str, nonGlobalRegex)], [
Object.assign(['b'], { index: 2, input: str, groups: undefined }),
]);
assert.throws(() => matchAll(str, nonGlobalRegex)); // non-global regexes throw

matchAll.shim(); // will be a no-op if not needed

Expand All @@ -54,9 +52,7 @@ assert.deepEqual([...str.matchAll(globalRegex)], [
Object.assign(['c'], { index: 3, input: str, groups: undefined }),
]);

assert.deepEqual([...str.matchAll(nonGlobalRegex)], [
Object.assign(['b'], { index: 2, input: str, groups: undefined }),
]);
assert.throws(() => matchAll(str, nonGlobalRegex)); // non-global regexes throw

```

Expand Down
14 changes: 14 additions & 0 deletions implementation.js
@@ -1,7 +1,11 @@
'use strict';

var ES = require('es-abstract/es2019');
var callBound = require('es-abstract/helpers/callBound');
var hasSymbols = require('has-symbols')();
var flagsGetter = require('regexp.prototype.flags');

var $indexOf = callBound('String.prototype.indexOf');

var regexpMatchAllPolyfill = require('./polyfill-regexp-matchall');

Expand All @@ -24,6 +28,16 @@ module.exports = function matchAll(regexp) {
var O = ES.RequireObjectCoercible(this);

if (typeof regexp !== 'undefined' && regexp !== null) {
var isRegExp = ES.IsRegExp(regexp);
if (isRegExp) {
// workaround for older engines that lack RegExp.prototype.flags
var flags = 'flags' in regexp ? ES.Get(regexp, 'flags') : flagsGetter(regexp);
ES.RequireObjectCoercible(flags);
if ($indexOf(ES.ToString(flags), 'g') < 0) {
throw new TypeError('matchAll requires a non-global regular expression');
}
}

var matcher = getMatcher(regexp);
if (typeof matcher !== 'undefined') {
return ES.Call(matcher, regexp, [O]);
Expand Down
9 changes: 8 additions & 1 deletion polyfill.js
Expand Up @@ -3,5 +3,12 @@
var implementation = require('./implementation');

module.exports = function getPolyfill() {
return String.prototype.matchAll || implementation;
if (String.prototype.matchAll) {
try {
''.matchAll(RegExp.prototype);
} catch (e) {
return String.prototype.matchAll;
}
}
return implementation;
};
51 changes: 37 additions & 14 deletions test/tests.js
Expand Up @@ -110,14 +110,13 @@ module.exports = function (matchAll, regexMatchAll, t) {
var str = 'aabc';
var regex = /[ac]/g;
if (define.supportsDescriptors) {
Object.defineProperty(regex, 'flags', { value: '' });
Object.defineProperty(regex, 'flags', { value: undefined });
}
s2t.equal(regex.flags, '', 'regex has an empty string "flags" property');
var expectedResults = [
{ value: assign(['a'], groups({ index: 0, input: str })), done: false },
{ value: undefined, done: true }
];
testResults(s2t, matchAll(str, regex), expectedResults);
s2t.equal(regex.flags, undefined, 'regex has an undefined "flags" property');
s2t['throws'](
function () { matchAll(str, regex); },
'undefined flags throws'
);
s2t.end();
});

Expand Down Expand Up @@ -156,11 +155,25 @@ module.exports = function (matchAll, regexMatchAll, t) {
s2t.end();
});

st.test('works with a non-global non-sticky regex', function (s2t) {
st.test('throws with a non-global regex', function (s2t) {
var str = 'AaBbCc';
var regex = /[bc]/i;
s2t['throws'](
function () { matchAll(str, regex); },
TypeError,
'a non-global regex throws'
);
s2t.end();
});

st.test('works with a global non-sticky regex', function (s2t) {
var str = 'AaBbCc';
var regex = /[bc]/gi;
var expectedResults = [
{ value: assign(['B'], groups({ index: 2, input: str })), done: false },
{ value: assign(['b'], groups({ index: 3, input: str })), done: false },
{ value: assign(['C'], groups({ index: 4, input: str })), done: false },
{ value: assign(['c'], groups({ index: 5, input: str })), done: false },
{ value: undefined, done: true }
];
testResults(s2t, matchAll(str, regex), expectedResults);
Expand Down Expand Up @@ -205,17 +218,27 @@ module.exports = function (matchAll, regexMatchAll, t) {
var expectedResults = [
{ value: undefined, done: true }
];

/* eslint no-invalid-regexp: [2, { "allowConstructorFlags": ["y"] }] */
var regex = new RegExp('\\B', 'y');
s2t['throws'](
function () { matchAll(str, regex); },
TypeError,
'non-global sticky regex throws'
);

/* eslint no-invalid-regexp: [2, { "allowConstructorFlags": ["y"] }] */
testResults(s2t, matchAll(str, new RegExp('\\B', 'y')), expectedResults);
testResults(s2t, matchAll(str, new RegExp('\\B', 'gy')), expectedResults);

s2t.end();
});

st.test('unflagged', function (s2t) {
var expectedResults = [
{ value: assign([''], groups({ index: 1, input: str })), done: false },
{ value: undefined, done: true }
];
testResults(s2t, matchAll(str, /\B/), expectedResults);
s2t['throws'](
function () { matchAll(str, /\B/); },
TypeError,
'unflagged regex throws'
);
s2t.end();
});

Expand Down

0 comments on commit c1717e6

Please sign in to comment.