LibJS: Implement most Intl.Locale.Prototype.<<keyword>> properties

The keyword accessors all have the same function body in the spec,
except for the Intl.Locale method they invoke. This generates those
properties in the same manner as RegExp.prototype.

    Intl.Locale.prototype.calendar
    Intl.Locale.prototype.caseFirst
    Intl.Locale.prototype.collation
    Intl.Locale.prototype.hourCycle
    Intl.Locale.prototype.numberingSystem

The exception is Intl.Locale.prototype.numeric, which will be defined
separately because it is a boolean value.
This commit is contained in:
Timothy Flynn 2021-09-02 10:49:06 -04:00 committed by Linus Groh
parent 21b3c5edba
commit d7825f3680
Notes: sideshowbarker 2024-07-18 04:53:04 +09:00
7 changed files with 117 additions and 0 deletions

View file

@ -47,6 +47,11 @@ void LocalePrototype::initialize(GlobalObject& global_object)
define_direct_property(*vm.well_known_symbol_to_string_tag(), js_string(vm, "Intl.Locale"), Attribute::Configurable);
define_native_accessor(vm.names.baseName, base_name, {}, Attribute::Configurable);
define_native_accessor(vm.names.calendar, calendar, {}, Attribute::Configurable);
define_native_accessor(vm.names.caseFirst, case_first, {}, Attribute::Configurable);
define_native_accessor(vm.names.collation, collation, {}, Attribute::Configurable);
define_native_accessor(vm.names.hourCycle, hour_cycle, {}, Attribute::Configurable);
define_native_accessor(vm.names.numberingSystem, numbering_system, {}, Attribute::Configurable);
}
// 14.3.5 Intl.Locale.prototype.toString ( ), https://tc39.es/ecma402/#sec-Intl.Locale.prototype.toString
@ -79,4 +84,29 @@ JS_DEFINE_NATIVE_GETTER(LocalePrototype::base_name)
return js_string(vm, locale->language_id.to_string());
}
#define JS_ENUMERATE_LOCALE_KEYWORD_PROPERTIES \
__JS_ENUMERATE(calendar) \
__JS_ENUMERATE(case_first) \
__JS_ENUMERATE(collation) \
__JS_ENUMERATE(hour_cycle) \
__JS_ENUMERATE(numbering_system)
// 14.3.7 get Intl.Locale.prototype.calendar, https://tc39.es/ecma402/#sec-Intl.Locale.prototype.calendar
// 14.3.8 get Intl.Locale.prototype.caseFirst, https://tc39.es/ecma402/#sec-Intl.Locale.prototype.caseFirst
// 14.3.9 get Intl.Locale.prototype.collation, https://tc39.es/ecma402/#sec-Intl.Locale.prototype.collation
// 14.3.10 get Intl.Locale.prototype.hourCycle, https://tc39.es/ecma402/#sec-Intl.Locale.prototype.hourCycle
// 14.3.12 get Intl.Locale.prototype.numberingSystem, https://tc39.es/ecma402/#sec-Intl.Locale.prototype.numberingSystem
#define __JS_ENUMERATE(keyword) \
JS_DEFINE_NATIVE_GETTER(LocalePrototype::keyword) \
{ \
auto* locale_object = typed_this(global_object); \
if (!locale_object) \
return {}; \
if (!locale_object->has_##keyword()) \
return js_undefined(); \
return js_string(vm, locale_object->keyword()); \
}
JS_ENUMERATE_LOCALE_KEYWORD_PROPERTIES
#undef __JS_ENUMERATE
}

View file

@ -22,6 +22,11 @@ private:
JS_DECLARE_NATIVE_FUNCTION(to_string);
JS_DECLARE_NATIVE_GETTER(base_name);
JS_DECLARE_NATIVE_GETTER(calendar);
JS_DECLARE_NATIVE_GETTER(case_first);
JS_DECLARE_NATIVE_GETTER(collation);
JS_DECLARE_NATIVE_GETTER(hour_cycle);
JS_DECLARE_NATIVE_GETTER(numbering_system);
};
}

View file

@ -0,0 +1,16 @@
describe("errors", () => {
test("called on non-Locale object", () => {
expect(() => {
Intl.Locale.prototype.calendar;
}).toThrowWithMessage(TypeError, "Not a Intl.Locale object");
});
});
describe("normal behavior", () => {
test("basic functionality", () => {
expect(new Intl.Locale("en").calendar).toBeUndefined();
expect(new Intl.Locale("en-u-ca-abc").calendar).toBe("abc");
expect(new Intl.Locale("en", { calendar: "abc" }).calendar).toBe("abc");
expect(new Intl.Locale("en-u-ca-abc", { calendar: "def" }).calendar).toBe("def");
});
});

View file

@ -0,0 +1,16 @@
describe("errors", () => {
test("called on non-Locale object", () => {
expect(() => {
Intl.Locale.prototype.caseFirst;
}).toThrowWithMessage(TypeError, "Not a Intl.Locale object");
});
});
describe("normal behavior", () => {
test("basic functionality", () => {
expect(new Intl.Locale("en").caseFirst).toBeUndefined();
expect(new Intl.Locale("en-u-kf-upper").caseFirst).toBe("upper");
expect(new Intl.Locale("en", { caseFirst: "lower" }).caseFirst).toBe("lower");
expect(new Intl.Locale("en-u-kf-upper", { caseFirst: "false" }).caseFirst).toBe("false");
});
});

View file

@ -0,0 +1,16 @@
describe("errors", () => {
test("called on non-Locale object", () => {
expect(() => {
Intl.Locale.prototype.collation;
}).toThrowWithMessage(TypeError, "Not a Intl.Locale object");
});
});
describe("normal behavior", () => {
test("basic functionality", () => {
expect(new Intl.Locale("en").collation).toBeUndefined();
expect(new Intl.Locale("en-u-co-abc").collation).toBe("abc");
expect(new Intl.Locale("en", { collation: "abc" }).collation).toBe("abc");
expect(new Intl.Locale("en-u-co-abc", { collation: "def" }).collation).toBe("def");
});
});

View file

@ -0,0 +1,16 @@
describe("errors", () => {
test("called on non-Locale object", () => {
expect(() => {
Intl.Locale.prototype.hourCycle;
}).toThrowWithMessage(TypeError, "Not a Intl.Locale object");
});
});
describe("normal behavior", () => {
test("basic functionality", () => {
expect(new Intl.Locale("en").hourCycle).toBeUndefined();
expect(new Intl.Locale("en-u-hc-h11").hourCycle).toBe("h11");
expect(new Intl.Locale("en", { hourCycle: "h12" }).hourCycle).toBe("h12");
expect(new Intl.Locale("en-u-hc-h23", { hourCycle: "h24" }).hourCycle).toBe("h24");
});
});

View file

@ -0,0 +1,18 @@
describe("errors", () => {
test("called on non-Locale object", () => {
expect(() => {
Intl.Locale.prototype.numberingSystem;
}).toThrowWithMessage(TypeError, "Not a Intl.Locale object");
});
});
describe("normal behavior", () => {
test("basic functionality", () => {
expect(new Intl.Locale("en").numberingSystem).toBeUndefined();
expect(new Intl.Locale("en-u-nu-abc").numberingSystem).toBe("abc");
expect(new Intl.Locale("en", { numberingSystem: "abc" }).numberingSystem).toBe("abc");
expect(new Intl.Locale("en-u-nu-abc", { numberingSystem: "def" }).numberingSystem).toBe(
"def"
);
});
});