Jelajahi Sumber

LibJS: Implement Intl.Locale.prototype.textInfo property

Timothy Flynn 3 tahun lalu
induk
melakukan
88a560dd84

+ 2 - 0
Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h

@@ -139,6 +139,7 @@ namespace JS {
     P(deleteProperty)                        \
     P(deref)                                 \
     P(description)                           \
+    P(direction)                             \
     P(disambiguation)                        \
     P(done)                                  \
     P(dotAll)                                \
@@ -469,6 +470,7 @@ namespace JS {
     P(tan)                                   \
     P(tanh)                                  \
     P(test)                                  \
+    P(textInfo)                              \
     P(then)                                  \
     P(time)                                  \
     P(timeEnd)                               \

+ 19 - 0
Userland/Libraries/LibJS/Runtime/Intl/Locale.cpp

@@ -167,4 +167,23 @@ Array* time_zones_of_locale(GlobalObject& global_object, StringView region)
     });
 }
 
+// 1.1.7 CharacterDirectionOfLocale ( loc ), https://tc39.es/proposal-intl-locale-info/#sec-character-direction-of-locale
+StringView character_direction_of_locale(Locale const& locale_object)
+{
+    // 1. Let locale be loc.[[Locale]].
+    auto const& locale = locale_object.locale();
+
+    // 2. Assert: locale matches the unicode_locale_id production.
+    VERIFY(Unicode::parse_unicode_locale_id(locale).has_value());
+
+    // 3. If the default general ordering of characters (characterOrder) within a line in locale is right-to-left, return "rtl".
+    // NOTE: LibUnicode handles both LTR and RTL character orders in this call, not just RTL. We then fallback to LTR
+    //       below if LibUnicode doesn't conclusively know the character order for this locale.
+    if (auto character_order = Unicode::character_order_for_locale(locale); character_order.has_value())
+        return Unicode::character_order_to_string(*character_order);
+
+    // 4. Return "ltr".
+    return "ltr"sv;
+}
+
 }

+ 1 - 0
Userland/Libraries/LibJS/Runtime/Intl/Locale.h

@@ -79,5 +79,6 @@ Array* collations_of_locale(GlobalObject& global_object, Locale const& locale);
 Array* hour_cycles_of_locale(GlobalObject& global_object, Locale const& locale);
 Array* numbering_systems_of_locale(GlobalObject& global_object, Locale const& locale);
 Array* time_zones_of_locale(GlobalObject& global_object, StringView region);
+StringView character_direction_of_locale(Locale const& locale);
 
 }

+ 21 - 0
Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.cpp

@@ -48,6 +48,7 @@ void LocalePrototype::initialize(GlobalObject& global_object)
     define_native_accessor(vm.names.script, script, {}, Attribute::Configurable);
     define_native_accessor(vm.names.region, region, {}, Attribute::Configurable);
     define_native_accessor(vm.names.timeZones, time_zones, {}, Attribute::Configurable);
+    define_native_accessor(vm.names.textInfo, text_info, {}, Attribute::Configurable);
 }
 
 // 14.3.3 Intl.Locale.prototype.maximize ( ), https://tc39.es/ecma402/#sec-Intl.Locale.prototype.maximize
@@ -242,4 +243,24 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::time_zones)
     return time_zones_of_locale(global_object, locale->language_id.region.value());
 }
 
+// 1.4.21 get Intl.Locale.prototype.textInfo, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.textInfo
+JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::text_info)
+{
+    // 1. Let loc be the this value.
+    // 2. Perform ? RequireInternalSlot(loc, [[InitializedLocale]]).
+    auto* locale_object = TRY(typed_this_object(global_object));
+
+    // 3. Let info be ! ObjectCreate(%Object.prototype%).
+    auto* info = Object::create(global_object, global_object.object_prototype());
+
+    // 4. Let dir be ! CharacterDirectionOfLocale(loc).
+    auto direction = character_direction_of_locale(*locale_object);
+
+    // 5. Perform ! CreateDataPropertyOrThrow(info, "direction", dir).
+    MUST(info->create_data_property_or_throw(vm.names.direction, js_string(vm, direction)));
+
+    // 6. Return info.
+    return info;
+}
+
 }

+ 1 - 0
Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.h

@@ -39,6 +39,7 @@ private:
     JS_DECLARE_NATIVE_FUNCTION(script);
     JS_DECLARE_NATIVE_FUNCTION(region);
     JS_DECLARE_NATIVE_FUNCTION(time_zones);
+    JS_DECLARE_NATIVE_FUNCTION(text_info);
 };
 
 }

+ 26 - 0
Userland/Libraries/LibJS/Tests/builtins/Intl/Locale/Locale.prototype.textInfo.js

@@ -0,0 +1,26 @@
+describe("errors", () => {
+    test("called on non-Locale object", () => {
+        expect(() => {
+            Intl.Locale.prototype.textInfo;
+        }).toThrowWithMessage(TypeError, "Not an object of type Intl.Locale");
+    });
+});
+
+describe("normal behavior", () => {
+    test("basic functionality", () => {
+        const textInfo = new Intl.Locale("en").textInfo;
+
+        expect(textInfo).toBeDefined();
+        expect(Object.getPrototypeOf(textInfo)).toBe(Object.prototype);
+
+        expect(textInfo.direction).toBeDefined();
+        expect(Object.getPrototypeOf(textInfo.direction)).toBe(String.prototype);
+
+        expect(textInfo.direction).toBe("ltr");
+        expect(new Intl.Locale("ar").textInfo.direction).toBe("rtl");
+    });
+
+    test("fallback to ltr", () => {
+        expect(new Intl.Locale("xx").textInfo.direction).toBe("ltr");
+    });
+});