es.string.match-all.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. 'use strict';
  2. /* eslint-disable es/no-string-prototype-matchall -- safe */
  3. var $ = require('../internals/export');
  4. var call = require('../internals/function-call');
  5. var uncurryThis = require('../internals/function-uncurry-this-clause');
  6. var createIteratorConstructor = require('../internals/iterator-create-constructor');
  7. var createIterResultObject = require('../internals/create-iter-result-object');
  8. var requireObjectCoercible = require('../internals/require-object-coercible');
  9. var toLength = require('../internals/to-length');
  10. var toString = require('../internals/to-string');
  11. var anObject = require('../internals/an-object');
  12. var isNullOrUndefined = require('../internals/is-null-or-undefined');
  13. var classof = require('../internals/classof-raw');
  14. var isRegExp = require('../internals/is-regexp');
  15. var getRegExpFlags = require('../internals/regexp-get-flags');
  16. var getMethod = require('../internals/get-method');
  17. var defineBuiltIn = require('../internals/define-built-in');
  18. var fails = require('../internals/fails');
  19. var wellKnownSymbol = require('../internals/well-known-symbol');
  20. var speciesConstructor = require('../internals/species-constructor');
  21. var advanceStringIndex = require('../internals/advance-string-index');
  22. var regExpExec = require('../internals/regexp-exec-abstract');
  23. var InternalStateModule = require('../internals/internal-state');
  24. var IS_PURE = require('../internals/is-pure');
  25. var MATCH_ALL = wellKnownSymbol('matchAll');
  26. var REGEXP_STRING = 'RegExp String';
  27. var REGEXP_STRING_ITERATOR = REGEXP_STRING + ' Iterator';
  28. var setInternalState = InternalStateModule.set;
  29. var getInternalState = InternalStateModule.getterFor(REGEXP_STRING_ITERATOR);
  30. var RegExpPrototype = RegExp.prototype;
  31. var $TypeError = TypeError;
  32. var stringIndexOf = uncurryThis(''.indexOf);
  33. var nativeMatchAll = uncurryThis(''.matchAll);
  34. var WORKS_WITH_NON_GLOBAL_REGEX = !!nativeMatchAll && !fails(function () {
  35. nativeMatchAll('a', /./);
  36. });
  37. var $RegExpStringIterator = createIteratorConstructor(function RegExpStringIterator(regexp, string, $global, fullUnicode) {
  38. setInternalState(this, {
  39. type: REGEXP_STRING_ITERATOR,
  40. regexp: regexp,
  41. string: string,
  42. global: $global,
  43. unicode: fullUnicode,
  44. done: false
  45. });
  46. }, REGEXP_STRING, function next() {
  47. var state = getInternalState(this);
  48. if (state.done) return createIterResultObject(undefined, true);
  49. var R = state.regexp;
  50. var S = state.string;
  51. var match = regExpExec(R, S);
  52. if (match === null) {
  53. state.done = true;
  54. return createIterResultObject(undefined, true);
  55. }
  56. if (state.global) {
  57. if (toString(match[0]) === '') R.lastIndex = advanceStringIndex(S, toLength(R.lastIndex), state.unicode);
  58. return createIterResultObject(match, false);
  59. }
  60. state.done = true;
  61. return createIterResultObject(match, false);
  62. });
  63. var $matchAll = function (string) {
  64. var R = anObject(this);
  65. var S = toString(string);
  66. var C = speciesConstructor(R, RegExp);
  67. var flags = toString(getRegExpFlags(R));
  68. var matcher, $global, fullUnicode;
  69. matcher = new C(C === RegExp ? R.source : R, flags);
  70. $global = !!~stringIndexOf(flags, 'g');
  71. fullUnicode = !!~stringIndexOf(flags, 'u');
  72. matcher.lastIndex = toLength(R.lastIndex);
  73. return new $RegExpStringIterator(matcher, S, $global, fullUnicode);
  74. };
  75. // `String.prototype.matchAll` method
  76. // https://tc39.es/ecma262/#sec-string.prototype.matchall
  77. $({ target: 'String', proto: true, forced: WORKS_WITH_NON_GLOBAL_REGEX }, {
  78. matchAll: function matchAll(regexp) {
  79. var O = requireObjectCoercible(this);
  80. var flags, S, matcher, rx;
  81. if (!isNullOrUndefined(regexp)) {
  82. if (isRegExp(regexp)) {
  83. flags = toString(requireObjectCoercible(getRegExpFlags(regexp)));
  84. if (!~stringIndexOf(flags, 'g')) throw new $TypeError('`.matchAll` does not allow non-global regexes');
  85. }
  86. if (WORKS_WITH_NON_GLOBAL_REGEX) return nativeMatchAll(O, regexp);
  87. matcher = getMethod(regexp, MATCH_ALL);
  88. if (matcher === undefined && IS_PURE && classof(regexp) === 'RegExp') matcher = $matchAll;
  89. if (matcher) return call(matcher, regexp, O);
  90. } else if (WORKS_WITH_NON_GLOBAL_REGEX) return nativeMatchAll(O, regexp);
  91. S = toString(O);
  92. rx = new RegExp(regexp, 'g');
  93. return IS_PURE ? call($matchAll, rx, S) : rx[MATCH_ALL](S);
  94. }
  95. });
  96. IS_PURE || MATCH_ALL in RegExpPrototype || defineBuiltIn(RegExpPrototype, MATCH_ALL, $matchAll);