diff --git a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h index 62f6f08f10..bbecddace1 100644 --- a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h +++ b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h @@ -145,6 +145,7 @@ M(RegExpObjectRepeatedFlag, "Repeated RegExp flag '{}'") \ M(SpeciesConstructorDidNotCreate, "Species constructor did not create {}") \ M(SpeciesConstructorReturned, "Species constructor returned {}") \ + M(StringMatchAllNonGlobalRegExp, "RegExp argument is non-global") \ M(StringRawCannotConvert, "Cannot convert property 'raw' to object from {}") \ M(StringRepeatCountMustBe, "repeat count must be a {} number") \ M(ThisHasNotBeenInitialized, "|this| has not been initialized") \ diff --git a/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp b/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp index 230498838e..4e42a7b786 100644 --- a/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp @@ -79,6 +79,7 @@ void StringPrototype::initialize(GlobalObject& global_object) define_native_function(vm.names.lastIndexOf, last_index_of, 1, attr); define_native_function(vm.names.at, at, 1, attr); define_native_function(vm.names.match, match, 1, attr); + define_native_function(vm.names.matchAll, match_all, 1, attr); define_native_function(vm.names.replace, replace, 2, attr); define_native_function(vm.names.anchor, anchor, 1, attr); define_native_function(vm.names.big, big, 0, attr); @@ -711,6 +712,46 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::match) return rx->invoke(vm.well_known_symbol_match(), js_string(vm, s)); } +// 22.1.3.12 String.prototype.matchAll ( regexp ), https://tc39.es/ecma262/#sec-string.prototype.matchall +JS_DEFINE_NATIVE_FUNCTION(StringPrototype::match_all) +{ + auto this_object = require_object_coercible(global_object, vm.this_value(global_object)); + if (vm.exception()) + return {}; + auto regexp = vm.argument(0); + if (!regexp.is_nullish()) { + auto is_regexp = regexp.is_regexp(global_object); + if (vm.exception()) + return {}; + if (is_regexp) { + auto flags = regexp.as_object().get("flags").value_or(js_undefined()); + if (vm.exception()) + return {}; + auto flags_object = require_object_coercible(global_object, flags); + if (vm.exception()) + return {}; + auto flags_string = flags_object.to_string(global_object); + if (vm.exception()) + return {}; + if (!flags_string.contains("g")) { + vm.throw_exception(global_object, ErrorType::StringMatchAllNonGlobalRegExp); + return {}; + } + } + if (auto* matcher = get_method(global_object, regexp, vm.well_known_symbol_match_all())) + return vm.call(*matcher, regexp, this_object); + if (vm.exception()) + return {}; + } + auto s = this_object.to_string(global_object); + if (vm.exception()) + return {}; + auto rx = regexp_create(global_object, regexp, js_string(vm, "g")); + if (!rx) + return {}; + return rx->invoke(vm.well_known_symbol_match_all(), js_string(vm, s)); +} + // 22.1.3.17 String.prototype.replace ( searchValue, replaceValue ), https://tc39.es/ecma262/#sec-string.prototype.replace JS_DEFINE_NATIVE_FUNCTION(StringPrototype::replace) { diff --git a/Userland/Libraries/LibJS/Runtime/StringPrototype.h b/Userland/Libraries/LibJS/Runtime/StringPrototype.h index 16cbaedb42..e8ec94cc61 100644 --- a/Userland/Libraries/LibJS/Runtime/StringPrototype.h +++ b/Userland/Libraries/LibJS/Runtime/StringPrototype.h @@ -44,6 +44,7 @@ private: JS_DECLARE_NATIVE_FUNCTION(last_index_of); JS_DECLARE_NATIVE_FUNCTION(at); JS_DECLARE_NATIVE_FUNCTION(match); + JS_DECLARE_NATIVE_FUNCTION(match_all); JS_DECLARE_NATIVE_FUNCTION(replace); JS_DECLARE_NATIVE_FUNCTION(anchor); JS_DECLARE_NATIVE_FUNCTION(big);