mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 12:37:44 +00:00
LibJS: Implement String.prototype.toWellFormed
This commit is contained in:
parent
0bb46235a7
commit
3ee5217adc
4 changed files with 90 additions and 0 deletions
|
@ -526,6 +526,7 @@ namespace JS {
|
||||||
P(toTimeString) \
|
P(toTimeString) \
|
||||||
P(toUpperCase) \
|
P(toUpperCase) \
|
||||||
P(toUTCString) \
|
P(toUTCString) \
|
||||||
|
P(toWellFormed) \
|
||||||
P(toZonedDateTime) \
|
P(toZonedDateTime) \
|
||||||
P(toZonedDateTimeISO) \
|
P(toZonedDateTimeISO) \
|
||||||
P(trace) \
|
P(trace) \
|
||||||
|
|
|
@ -171,6 +171,7 @@ void StringPrototype::initialize(Realm& realm)
|
||||||
define_native_function(realm, vm.names.toLowerCase, to_lowercase, 0, attr);
|
define_native_function(realm, vm.names.toLowerCase, to_lowercase, 0, attr);
|
||||||
define_native_function(realm, vm.names.toString, to_string, 0, attr);
|
define_native_function(realm, vm.names.toString, to_string, 0, attr);
|
||||||
define_native_function(realm, vm.names.toUpperCase, to_uppercase, 0, attr);
|
define_native_function(realm, vm.names.toUpperCase, to_uppercase, 0, attr);
|
||||||
|
define_native_function(realm, vm.names.toWellFormed, to_well_formed, 0, attr);
|
||||||
define_native_function(realm, vm.names.trim, trim, 0, attr);
|
define_native_function(realm, vm.names.trim, trim, 0, attr);
|
||||||
define_native_function(realm, vm.names.trimEnd, trim_end, 0, attr);
|
define_native_function(realm, vm.names.trimEnd, trim_end, 0, attr);
|
||||||
define_native_function(realm, vm.names.trimStart, trim_start, 0, attr);
|
define_native_function(realm, vm.names.trimStart, trim_start, 0, attr);
|
||||||
|
@ -980,6 +981,46 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::to_uppercase)
|
||||||
return js_string(vm, move(uppercase));
|
return js_string(vm, move(uppercase));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 22.1.3.11 String.prototype.toWellFormed ( )
|
||||||
|
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::to_well_formed)
|
||||||
|
{
|
||||||
|
// 1. Let O be ? RequireObjectCoercible(this value).
|
||||||
|
// 2. Let S be ? ToString(O).
|
||||||
|
auto string = TRY(utf16_string_from(vm));
|
||||||
|
|
||||||
|
// 3. Let strLen be the length of S.
|
||||||
|
auto length = string.length_in_code_units();
|
||||||
|
|
||||||
|
// 4. Let k be 0.
|
||||||
|
size_t k = 0;
|
||||||
|
|
||||||
|
// 5. Let result be the empty String.
|
||||||
|
StringBuilder result;
|
||||||
|
|
||||||
|
// 6. Repeat, while k < strLen,
|
||||||
|
while (k < length) {
|
||||||
|
// a. Let cp be CodePointAt(S, k).
|
||||||
|
auto code_point = JS::code_point_at(string.view(), k);
|
||||||
|
|
||||||
|
// b. If cp.[[IsUnpairedSurrogate]] is true, then
|
||||||
|
if (code_point.is_unpaired_surrogate) {
|
||||||
|
// i. Set result to the string-concatenation of result and 0xFFFD (REPLACEMENT CHARACTER).
|
||||||
|
result.append_code_point(0xfffd);
|
||||||
|
}
|
||||||
|
// c. Else,
|
||||||
|
else {
|
||||||
|
// i. Set result to the string-concatenation of result and UTF16EncodeCodePoint(cp.[[CodePoint]]).
|
||||||
|
result.append_code_point(code_point.code_point);
|
||||||
|
}
|
||||||
|
|
||||||
|
// d. Set k to k + cp.[[CodeUnitCount]].
|
||||||
|
k += code_point.code_unit_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. Return result.
|
||||||
|
return js_string(vm, result.build());
|
||||||
|
}
|
||||||
|
|
||||||
ThrowCompletionOr<String> trim_string(VM& vm, Value input_value, TrimMode where)
|
ThrowCompletionOr<String> trim_string(VM& vm, Value input_value, TrimMode where)
|
||||||
{
|
{
|
||||||
// 1. Let str be ? RequireObjectCoercible(string).
|
// 1. Let str be ? RequireObjectCoercible(string).
|
||||||
|
|
|
@ -59,6 +59,7 @@ private:
|
||||||
JS_DECLARE_NATIVE_FUNCTION(to_lowercase);
|
JS_DECLARE_NATIVE_FUNCTION(to_lowercase);
|
||||||
JS_DECLARE_NATIVE_FUNCTION(to_string);
|
JS_DECLARE_NATIVE_FUNCTION(to_string);
|
||||||
JS_DECLARE_NATIVE_FUNCTION(to_uppercase);
|
JS_DECLARE_NATIVE_FUNCTION(to_uppercase);
|
||||||
|
JS_DECLARE_NATIVE_FUNCTION(to_well_formed);
|
||||||
JS_DECLARE_NATIVE_FUNCTION(trim);
|
JS_DECLARE_NATIVE_FUNCTION(trim);
|
||||||
JS_DECLARE_NATIVE_FUNCTION(trim_end);
|
JS_DECLARE_NATIVE_FUNCTION(trim_end);
|
||||||
JS_DECLARE_NATIVE_FUNCTION(trim_start);
|
JS_DECLARE_NATIVE_FUNCTION(trim_start);
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
describe("errors", () => {
|
||||||
|
test("called with value that cannot be converted to a string", () => {
|
||||||
|
expect(() => {
|
||||||
|
String.prototype.toWellFormed.call(Symbol.hasInstance);
|
||||||
|
}).toThrowWithMessage(TypeError, "Cannot convert symbol to string");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("basic functionality", () => {
|
||||||
|
test("ascii strings", () => {
|
||||||
|
expect("".toWellFormed()).toBe("");
|
||||||
|
expect("foo".toWellFormed()).toBe("foo");
|
||||||
|
expect("abcdefghi".toWellFormed()).toBe("abcdefghi");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("valid UTF-16 strings", () => {
|
||||||
|
expect("😀".toWellFormed()).toBe("😀");
|
||||||
|
expect("\ud83d\ude00".toWellFormed()).toBe("\ud83d\ude00");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("invalid UTF-16 strings", () => {
|
||||||
|
expect("😀".slice(0, 1).toWellFormed()).toBe("\ufffd");
|
||||||
|
expect("😀".slice(1, 2).toWellFormed()).toBe("\ufffd");
|
||||||
|
expect("\ud83d".toWellFormed()).toBe("\ufffd");
|
||||||
|
expect("\ude00".toWellFormed()).toBe("\ufffd");
|
||||||
|
expect("a\ud83d".toWellFormed()).toBe("a\ufffd");
|
||||||
|
expect("a\ude00".toWellFormed()).toBe("a\ufffd");
|
||||||
|
expect("\ud83da".toWellFormed()).toBe("\ufffda");
|
||||||
|
expect("\ude00a".toWellFormed()).toBe("\ufffda");
|
||||||
|
expect("a\ud83da".toWellFormed()).toBe("a\ufffda");
|
||||||
|
expect("a\ude00a".toWellFormed()).toBe("a\ufffda");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("object converted to a string", () => {
|
||||||
|
let toStringCalled = false;
|
||||||
|
|
||||||
|
const obj = {
|
||||||
|
toString: function () {
|
||||||
|
toStringCalled = true;
|
||||||
|
return "toString";
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(String.prototype.toWellFormed.call(obj)).toBe("toString");
|
||||||
|
expect(toStringCalled).toBeTrue();
|
||||||
|
});
|
||||||
|
});
|
Loading…
Add table
Add a link
Reference in a new issue