UNPKG

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