_fix-re-wks.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. 'use strict';
  2. require('./es6.regexp.exec');
  3. var redefine = require('./_redefine');
  4. var hide = require('./_hide');
  5. var fails = require('./_fails');
  6. var defined = require('./_defined');
  7. var wks = require('./_wks');
  8. var regexpExec = require('./_regexp-exec');
  9. var SPECIES = wks('species');
  10. var REPLACE_SUPPORTS_NAMED_GROUPS = !fails(function () {
  11. // #replace needs built-in support for named groups.
  12. // #match works fine because it just return the exec results, even if it has
  13. // a "grops" property.
  14. var re = /./;
  15. re.exec = function () {
  16. var result = [];
  17. result.groups = { a: '7' };
  18. return result;
  19. };
  20. return ''.replace(re, '$<a>') !== '7';
  21. });
  22. var SPLIT_WORKS_WITH_OVERWRITTEN_EXEC = (function () {
  23. // Chrome 51 has a buggy "split" implementation when RegExp#exec !== nativeExec
  24. var re = /(?:)/;
  25. var originalExec = re.exec;
  26. re.exec = function () { return originalExec.apply(this, arguments); };
  27. var result = 'ab'.split(re);
  28. return result.length === 2 && result[0] === 'a' && result[1] === 'b';
  29. })();
  30. module.exports = function (KEY, length, exec) {
  31. var SYMBOL = wks(KEY);
  32. var DELEGATES_TO_SYMBOL = !fails(function () {
  33. // String methods call symbol-named RegEp methods
  34. var O = {};
  35. O[SYMBOL] = function () { return 7; };
  36. return ''[KEY](O) != 7;
  37. });
  38. var DELEGATES_TO_EXEC = DELEGATES_TO_SYMBOL ? !fails(function () {
  39. // Symbol-named RegExp methods call .exec
  40. var execCalled = false;
  41. var re = /a/;
  42. re.exec = function () { execCalled = true; return null; };
  43. if (KEY === 'split') {
  44. // RegExp[@@split] doesn't call the regex's exec method, but first creates
  45. // a new one. We need to return the patched regex when creating the new one.
  46. re.constructor = {};
  47. re.constructor[SPECIES] = function () { return re; };
  48. }
  49. re[SYMBOL]('');
  50. return !execCalled;
  51. }) : undefined;
  52. if (
  53. !DELEGATES_TO_SYMBOL ||
  54. !DELEGATES_TO_EXEC ||
  55. (KEY === 'replace' && !REPLACE_SUPPORTS_NAMED_GROUPS) ||
  56. (KEY === 'split' && !SPLIT_WORKS_WITH_OVERWRITTEN_EXEC)
  57. ) {
  58. var nativeRegExpMethod = /./[SYMBOL];
  59. var fns = exec(
  60. defined,
  61. SYMBOL,
  62. ''[KEY],
  63. function maybeCallNative(nativeMethod, regexp, str, arg2, forceStringMethod) {
  64. if (regexp.exec === regexpExec) {
  65. if (DELEGATES_TO_SYMBOL && !forceStringMethod) {
  66. // The native String method already delegates to @@method (this
  67. // polyfilled function), leasing to infinite recursion.
  68. // We avoid it by directly calling the native @@method method.
  69. return { done: true, value: nativeRegExpMethod.call(regexp, str, arg2) };
  70. }
  71. return { done: true, value: nativeMethod.call(str, regexp, arg2) };
  72. }
  73. return { done: false };
  74. }
  75. );
  76. var strfn = fns[0];
  77. var rxfn = fns[1];
  78. redefine(String.prototype, KEY, strfn);
  79. hide(RegExp.prototype, SYMBOL, length == 2
  80. // 21.2.5.8 RegExp.prototype[@@replace](string, replaceValue)
  81. // 21.2.5.11 RegExp.prototype[@@split](string, limit)
  82. ? function (string, arg) { return rxfn.call(string, this, arg); }
  83. // 21.2.5.6 RegExp.prototype[@@match](string)
  84. // 21.2.5.9 RegExp.prototype[@@search](string)
  85. : function (string) { return rxfn.call(string, this); }
  86. );
  87. }
  88. };