diff --git a/boa_engine/src/builtins/string/mod.rs b/boa_engine/src/builtins/string/mod.rs index efeeda192af..ade4f914ae3 100644 --- a/boa_engine/src/builtins/string/mod.rs +++ b/boa_engine/src/builtins/string/mod.rs @@ -123,6 +123,7 @@ impl IntrinsicObject for String { .method(Self::ends_with, "endsWith", 1) .method(Self::includes, "includes", 1) .method(Self::index_of, "indexOf", 1) + .method(Self::is_well_formed, "isWellFormed", 0) .method(Self::last_index_of, "lastIndexOf", 1) .method(Self::locale_compare, "localeCompare", 1) .method(Self::r#match, "match", 1) @@ -132,6 +133,7 @@ impl IntrinsicObject for String { .method(Self::trim, "trim", 0) .method(Self::to_case::, "toLowerCase", 0) .method(Self::to_case::, "toUpperCase", 0) + .method(Self::to_well_formed, "toWellFormed", 0) .method(Self::to_locale_case::, "toLocaleLowerCase", 0) .method(Self::to_locale_case::, "toLocaleUpperCase", 0) .method(Self::substring, "substring", 2) @@ -1289,6 +1291,34 @@ impl String { .into()) } + /// `String.prototype.isWellFormed ( )` + /// + /// More information: + /// - [ECMAScript reference][spec] + /// - [MDN documentation][mdn] + /// + /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.iswellformed + /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/isWellFormed + pub(crate) fn is_well_formed( + this: &JsValue, + _: &[JsValue], + context: &mut Context<'_>, + ) -> JsResult { + // 1. Let O be ? RequireObjectCoercible(this value). + let o = this.require_object_coercible()?; + + // 2. Let S be ? ToString(O). + let s = o.to_string(context)?; + + // 3. Return IsStringWellFormedUnicode(S). + for code_point in s.code_points() { + if let CodePoint::UnpairedSurrogate(_) = code_point { + return Ok(false.into()); + } + } + Ok(true.into()) + } + /// `String.prototype.lastIndexOf( searchValue[, fromIndex] )` /// /// The `lastIndexOf()` method returns the index within the calling `String` object of the last occurrence @@ -1772,6 +1802,47 @@ impl String { } } + /// `String.prototype.toWellFormed ( )` + /// + /// More information: + /// - [ECMAScript reference][spec] + /// - [MDN documentation][mdn] + /// + /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.towellformed + /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toWellFormed + pub(crate) fn to_well_formed( + this: &JsValue, + _: &[JsValue], + context: &mut Context<'_>, + ) -> JsResult { + // 1. Let O be ? RequireObjectCoercible(this value). + let o = this.require_object_coercible()?; + + // 2. Let S be ? ToString(O). + let s = o.to_string(context)?; + + // 3. Let strLen be the length of S. + // 4. Let k be 0. + // 5. Let result be the empty String. + // 6. Repeat, while k < strLen, + // a. Let cp be CodePointAt(S, k). + // b. If cp.[[IsUnpairedSurrogate]] is true, then + // i. Set result to the string-concatenation of result and 0xFFFD (REPLACEMENT CHARACTER). + // c. Else, + // i. Set result to the string-concatenation of result and UTF16EncodeCodePoint(cp.[[CodePoint]]). + // d. Set k to k + cp.[[CodeUnitCount]]. + let result = s + .code_points() + .map(|code_point| match code_point { + CodePoint::UnpairedSurrogate(_) => '\u{FFFD}', + CodePoint::Unicode(char) => char, + }) + .collect::(); + + // 7. Return result. + Ok(result.into()) + } + /// `String.prototype.substring( indexStart[, indexEnd] )` /// /// The `substring()` method returns the part of the `string` between the start and end indexes, or to the end of the string. diff --git a/test_ignore.toml b/test_ignore.toml index 1eff630e464..dc4967b8a2d 100644 --- a/test_ignore.toml +++ b/test_ignore.toml @@ -9,8 +9,6 @@ features = [ "IsHTMLDDA", "Atomics", "change-array-by-copy", - "String.prototype.isWellFormed", - "String.prototype.toWellFormed", "symbols-as-weakmap-keys", "intl-normative-optional", "Intl.DisplayNames",