es.string.replace-all.js 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. 'use strict';
  2. var $ = require('../internals/export');
  3. var global = require('../internals/global');
  4. var call = require('../internals/function-call');
  5. var uncurryThis = require('../internals/function-uncurry-this');
  6. var requireObjectCoercible = require('../internals/require-object-coercible');
  7. var isCallable = require('../internals/is-callable');
  8. var isRegExp = require('../internals/is-regexp');
  9. var toString = require('../internals/to-string');
  10. var getMethod = require('../internals/get-method');
  11. var regExpFlags = require('../internals/regexp-flags');
  12. var getSubstitution = require('../internals/get-substitution');
  13. var wellKnownSymbol = require('../internals/well-known-symbol');
  14. var IS_PURE = require('../internals/is-pure');
  15. var REPLACE = wellKnownSymbol('replace');
  16. var RegExpPrototype = RegExp.prototype;
  17. var TypeError = global.TypeError;
  18. var getFlags = uncurryThis(regExpFlags);
  19. var indexOf = uncurryThis(''.indexOf);
  20. var replace = uncurryThis(''.replace);
  21. var stringSlice = uncurryThis(''.slice);
  22. var max = Math.max;
  23. var stringIndexOf = function (string, searchValue, fromIndex) {
  24. if (fromIndex > string.length) return -1;
  25. if (searchValue === '') return fromIndex;
  26. return indexOf(string, searchValue, fromIndex);
  27. };
  28. // `String.prototype.replaceAll` method
  29. // https://tc39.es/ecma262/#sec-string.prototype.replaceall
  30. $({ target: 'String', proto: true }, {
  31. replaceAll: function replaceAll(searchValue, replaceValue) {
  32. var O = requireObjectCoercible(this);
  33. var IS_REG_EXP, flags, replacer, string, searchString, functionalReplace, searchLength, advanceBy, replacement;
  34. var position = 0;
  35. var endOfLastMatch = 0;
  36. var result = '';
  37. if (searchValue != null) {
  38. IS_REG_EXP = isRegExp(searchValue);
  39. if (IS_REG_EXP) {
  40. flags = toString(requireObjectCoercible('flags' in RegExpPrototype
  41. ? searchValue.flags
  42. : getFlags(searchValue)
  43. ));
  44. if (!~indexOf(flags, 'g')) throw TypeError('`.replaceAll` does not allow non-global regexes');
  45. }
  46. replacer = getMethod(searchValue, REPLACE);
  47. if (replacer) {
  48. return call(replacer, searchValue, O, replaceValue);
  49. } else if (IS_PURE && IS_REG_EXP) {
  50. return replace(toString(O), searchValue, replaceValue);
  51. }
  52. }
  53. string = toString(O);
  54. searchString = toString(searchValue);
  55. functionalReplace = isCallable(replaceValue);
  56. if (!functionalReplace) replaceValue = toString(replaceValue);
  57. searchLength = searchString.length;
  58. advanceBy = max(1, searchLength);
  59. position = stringIndexOf(string, searchString, 0);
  60. while (position !== -1) {
  61. replacement = functionalReplace
  62. ? toString(replaceValue(searchString, position, string))
  63. : getSubstitution(searchString, string, position, [], undefined, replaceValue);
  64. result += stringSlice(string, endOfLastMatch, position) + replacement;
  65. endOfLastMatch = position + searchLength;
  66. position = stringIndexOf(string, searchString, position + advanceBy);
  67. }
  68. if (endOfLastMatch < string.length) {
  69. result += stringSlice(string, endOfLastMatch);
  70. }
  71. return result;
  72. }
  73. });