Skip to content

Commit

Permalink
[New] Ensure RegExp#toString is compliant.
Browse files Browse the repository at this point in the history
  • Loading branch information
ljharb committed Feb 12, 2016
1 parent 5333255 commit d310b25
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -47,6 +47,7 @@ In both browser and node you may also want to include `unorm`; see the [`String.
* `[Symbol.replace]` (requires native `Symbol`s)
* `[Symbol.search]` (requires native `Symbol`s)
* `[Symbol.split]` (requires native `Symbol`s)
* `toString`
* `Number`:
* binary and octal literals: `Number('0b1')` and `Number('0o7')`
* `EPSILON`
Expand Down
20 changes: 20 additions & 0 deletions es6-shim.js
Expand Up @@ -1743,6 +1743,26 @@
return RegExp(regex) === regex;
}());

var regexToStringIsGeneric = valueOrFalseIfThrows(function () {
return RegExp.prototype.toString.call({ source: 'abc' }) === '/abc/';
});
var regexToStringSupportsGenericFlags = regexToStringIsGeneric && valueOrFalseIfThrows(function () {
return RegExp.prototype.toString.call({ source: 'a', flags: 'b' }) === '/a/b';
});
if (!regexToStringIsGeneric || !regexToStringSupportsGenericFlags) {
var origRegExpToString = RegExp.prototype.toString;
defineProperty(RegExp.prototype, 'toString', function toString() {
var R = ES.RequireObjectCoercible(this);
if (Type.regex(R)) {
return _call(origRegExpToString, R);
}
var pattern = $String(R.source);
var flags = $String(R.flags);
return '/' + pattern + '/' + flags;
}, true);
Value.preserveToString(RegExp.prototype.toString, origRegExpToString);
}

if (supportsDescriptors && (!regExpSupportsFlagsWithRegex || regExpNeedsToSupportSymbolMatch)) {
var flagsGetter = Object.getOwnPropertyDescriptor(RegExp.prototype, 'flags').get;
var sourceDesc = Object.getOwnPropertyDescriptor(RegExp.prototype, 'source') || {};
Expand Down
29 changes: 29 additions & 0 deletions test/regexp.js
Expand Up @@ -269,6 +269,35 @@ describe('RegExp', function () {
});
});

describe('#toString()', function () {
it('throws on null/undefined', function () {
expect(function () { RegExp.prototype.toString.call(null); }).to['throw'](TypeError);
expect(function () { RegExp.prototype.toString.call(undefined); }).to['throw'](TypeError);
});

it('works on regexes', function () {
expect(RegExp.prototype.toString.call(/a/g)).to.equal('/a/g');
expect(RegExp.prototype.toString.call(new RegExp('a', 'g'))).to.equal('/a/g');
});

it('works on non-regexes', function () {
expect(RegExp.prototype.toString.call({ source: 'abc', flags: '' })).to.equal('/abc/');
expect(RegExp.prototype.toString.call({ source: 'abc', flags: 'xyz' })).to.equal('/abc/xyz');
});

ifSymbolsDescribe('Symbol.match', function () {
if (!hasSymbols || typeof Symbol.match === 'undefined') {
return;
}

it('accepts a non-regex with Symbol.match', function () {
var obj = { source: 'abc', flags: 'def' };
obj[Symbol.match] = RegExp.prototype[Symbol.match];
expect(RegExp.prototype.toString.call(obj)).to.equal('/abc/def');
});
});
});

describe('Object properties', function () {
it('does not have the nonstandard $input property', function () {
expect(RegExp).not.to.have.property('$input'); // Chrome < 39, Opera < 26 have this
Expand Down

0 comments on commit d310b25

Please sign in to comment.