diff options
author | Idan Horowitz <idan.horowitz@gmail.com> | 2022-02-20 21:00:37 +0200 |
---|---|---|
committer | Tim Flynn <trflynn89@pm.me> | 2022-02-20 22:05:59 -0500 |
commit | 6558f4ae6bff4aa26f8fa768196e2d198e5b57f8 (patch) | |
tree | 0f5aab47ccdabddef37dc845bfa57c9db4abb555 | |
parent | 0bdb29326234a4cc89b2e14e3a2f83eb63ffb321 (diff) | |
download | serenity-6558f4ae6bff4aa26f8fa768196e2d198e5b57f8.zip |
LibJS: Implement get Intl.Collator.prototype.compare
5 files changed, 84 insertions, 7 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/Collator.cpp b/Userland/Libraries/LibJS/Runtime/Intl/Collator.cpp index 9ac7f50d20..b705d4adc5 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/Collator.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/Collator.cpp @@ -91,5 +91,10 @@ StringView Collator::case_first_string() const VERIFY_NOT_REACHED(); } } +void Collator::visit_edges(Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(m_bound_compare); +} } diff --git a/Userland/Libraries/LibJS/Runtime/Intl/Collator.h b/Userland/Libraries/LibJS/Runtime/Intl/Collator.h index 855ca650c6..cf72a86a8e 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/Collator.h +++ b/Userland/Libraries/LibJS/Runtime/Intl/Collator.h @@ -9,6 +9,7 @@ #include <AK/Array.h> #include <AK/String.h> #include <AK/StringView.h> +#include <LibJS/Runtime/Intl/CollatorCompareFunction.h> #include <LibJS/Runtime/Object.h> namespace JS::Intl { @@ -69,14 +70,20 @@ public: bool numeric() const { return m_numeric; } void set_numeric(bool numeric) { m_numeric = numeric; } + CollatorCompareFunction* bound_compare() const { return m_bound_compare; } + void set_bound_compare(CollatorCompareFunction* bound_compare) { m_bound_compare = bound_compare; } + private: - String m_locale; // [[Locale]] - Usage m_usage { Usage::Sort }; // [[Usage]] - Sensitivity m_sensitivity { Sensitivity::Variant }; // [[Sensitivity]] - CaseFirst m_case_first { CaseFirst::False }; // [[CaseFirst]] - String m_collation; // [[Collation]] - bool m_ignore_punctuation { false }; // [[IgnorePunctuation]] - bool m_numeric { false }; // [[Numeric]] + virtual void visit_edges(Visitor&) override; + + String m_locale; // [[Locale]] + Usage m_usage { Usage::Sort }; // [[Usage]] + Sensitivity m_sensitivity { Sensitivity::Variant }; // [[Sensitivity]] + CaseFirst m_case_first { CaseFirst::False }; // [[CaseFirst]] + String m_collation; // [[Collation]] + bool m_ignore_punctuation { false }; // [[IgnorePunctuation]] + bool m_numeric { false }; // [[Numeric]] + CollatorCompareFunction* m_bound_compare { nullptr }; // [[BoundCompare]] }; } diff --git a/Userland/Libraries/LibJS/Runtime/Intl/CollatorPrototype.cpp b/Userland/Libraries/LibJS/Runtime/Intl/CollatorPrototype.cpp index 8820d272eb..0c8295e023 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/CollatorPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/CollatorPrototype.cpp @@ -6,6 +6,7 @@ #include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/Intl/Collator.h> +#include <LibJS/Runtime/Intl/CollatorCompareFunction.h> #include <LibJS/Runtime/Intl/CollatorPrototype.h> namespace JS::Intl { @@ -26,9 +27,31 @@ void CollatorPrototype::initialize(GlobalObject& global_object) define_direct_property(*vm.well_known_symbol_to_string_tag(), js_string(vm, "Intl.Collator"), Attribute::Configurable); u8 attr = Attribute::Writable | Attribute::Configurable; + define_native_accessor(vm.names.compare, compare_getter, {}, attr); define_native_function(vm.names.resolvedOptions, resolved_options, 0, attr); } +// 10.3.3 get Intl.Collator.prototype.compare, https://tc39.es/ecma402/#sec-intl.collator.prototype.compare +JS_DEFINE_NATIVE_FUNCTION(CollatorPrototype::compare_getter) +{ + // 1. Let collator be the this value. + // 2. Perform ? RequireInternalSlot(collator, [[InitializedCollator]]). + auto* collator = TRY(typed_this_object(global_object)); + + // 3. If collator.[[BoundCompare]] is undefined, then + if (!collator->bound_compare()) { + // a. Let F be a new built-in function object as defined in 10.3.3.1. + // b. Set F.[[Collator]] to collator. + auto* function = CollatorCompareFunction::create(global_object, *collator); + + // c. Set collator.[[BoundCompare]] to F. + collator->set_bound_compare(function); + } + + // 4. Return collator.[[BoundCompare]]. + return collator->bound_compare(); +} + // 10.3.4 Intl.Collator.prototype.resolvedOptions ( ), https://tc39.es/ecma402/#sec-intl.collator.prototype.resolvedoptions JS_DEFINE_NATIVE_FUNCTION(CollatorPrototype::resolved_options) { diff --git a/Userland/Libraries/LibJS/Runtime/Intl/CollatorPrototype.h b/Userland/Libraries/LibJS/Runtime/Intl/CollatorPrototype.h index 334be0373a..4a9db4bc55 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/CollatorPrototype.h +++ b/Userland/Libraries/LibJS/Runtime/Intl/CollatorPrototype.h @@ -20,6 +20,7 @@ public: virtual ~CollatorPrototype() override = default; private: + JS_DECLARE_NATIVE_FUNCTION(compare_getter); JS_DECLARE_NATIVE_FUNCTION(resolved_options); }; diff --git a/Userland/Libraries/LibJS/Tests/builtins/Intl/Collator/Collator.prototype.compare.js b/Userland/Libraries/LibJS/Tests/builtins/Intl/Collator/Collator.prototype.compare.js new file mode 100644 index 0000000000..f98ff8b0ce --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/Intl/Collator/Collator.prototype.compare.js @@ -0,0 +1,41 @@ +describe("correct behavior", () => { + test("length is 2", () => { + expect(new Intl.Collator().compare).toHaveLength(2); + }); + + test("basic functionality", () => { + const collator = new Intl.Collator(); + expect(collator.compare("", "")).toBe(0); + expect(collator.compare("a", "a")).toBe(0); + expect(collator.compare("6", "6")).toBe(0); + + function compareBoth(a, b) { + const aTob = collator.compare(a, b); + const bToa = collator.compare(b, a); + + expect(aTob > 0).toBeTrue(); + expect(aTob).toBe(-bToa); + } + + compareBoth("a", ""); + compareBoth("1", ""); + compareBoth("a", "A"); + compareBoth("7", "3"); + compareBoth("0000", "0"); + + expect(collator.compare("undefined")).toBe(0); + expect(collator.compare("undefined", undefined)).toBe(0); + + expect(collator.compare("null", null)).toBe(0); + expect(collator.compare("null", undefined)).not.toBe(0); + expect(collator.compare("null") < 0).toBeTrue(); + }); + + test("UTF-16", () => { + const collator = new Intl.Collator(); + const string = "😀😀"; + expect(collator.compare(string, "😀😀")).toBe(0); + expect(collator.compare(string, "\ud83d") > 0); + expect(collator.compare(string, "😀😀s") < 0); + }); +}); |