diff --git a/README.md b/README.md index 6d37667b..840e8239 100644 --- a/README.md +++ b/README.md @@ -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` diff --git a/es6-shim.js b/es6-shim.js index add2730c..e3c5a782 100644 --- a/es6-shim.js +++ b/es6-shim.js @@ -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') || {}; diff --git a/test/regexp.js b/test/regexp.js index b79985cf..b7521e12 100644 --- a/test/regexp.js +++ b/test/regexp.js @@ -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