Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions nova_vm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ rand = { workspace = true }
ryu-js = { workspace = true }
small_string = { path = "../small_string" }
sonic-rs = { workspace = true, optional = true }
unicode-normalization = "0.1.24"
wtf8 = { workspace = true }

[features]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use std::{cmp::max, collections::VecDeque, iter::repeat};
use std::{cmp::max, collections::VecDeque, iter::repeat, str::FromStr};

use small_string::SmallString;
use unicode_normalization::UnicodeNormalization;

use crate::{
ecmascript::{
Expand Down Expand Up @@ -567,8 +568,42 @@ impl StringPrototype {
todo!()
}

fn normalize(_agent: &mut Agent, _this_value: Value, _: ArgumentsList) -> JsResult<Value> {
todo!()
/// ### [22.1.3.15 String.prototype.normalize ( \[ form \] )](https://tc39.es/ecma262/#sec-string.prototype.normalize)
fn normalize(
agent: &mut Agent,
this_value: Value,
arguments: ArgumentsList,
) -> JsResult<Value> {
// 1. Let O be ? RequireObjectCoercible(this value).
let o = require_object_coercible(agent, this_value)?;

// 2. Let S be ? ToString(O).
let s = to_string(agent, o)?;

// 3. If form is undefined, let f be "NFC".
let form = arguments.get(0);
let f = if form.is_undefined() {
NormalizeForm::NFC
} else {
// 4. Else, let f be ? ToString(form).
let form_result = NormalizeForm::from_str(form.to_string(agent).unwrap().as_str(agent));
let form = match form_result {
Ok(form) => form,
// 5. If f is not one of "NFC", "NFD", "NFKC", or "NFKD", throw a RangeError exception.
Err(()) => {
return Err(agent.throw_exception_with_static_message(
ExceptionType::RangeError,
"The normalization form should be one of NFC, NFD, NFKC, NFKD.",
))
}
};
form
};

// 6. Let ns be the String value that is the result of normalizing S into the normalization form named by f as specified in the latest Unicode Standard, Normalization Forms.
let ns = unicode_normalize(s.as_str(agent), f);
// 7. Return ns.
Ok(Value::from_string(agent, ns).into_value())
}

/// ### [22.1.3.16 String.prototype.padEnd ( maxLength \[ , fillString \] )](https://tc39.es/ecma262/#sec-string.prototype.padend)
Expand Down Expand Up @@ -1478,3 +1513,44 @@ enum TrimWhere {
End,
StartAndEnd,
}

enum NormalizeForm {
NFC,
NFD,
NFKC,
NFKD,
}

impl NormalizeForm {
fn as_str(&self) -> &'static str {
match self {
NormalizeForm::NFC => "NFC",
NormalizeForm::NFD => "NFD",
NormalizeForm::NFKC => "NFKC",
NormalizeForm::NFKD => "NFKD",
}
}
}

impl FromStr for NormalizeForm {
type Err = ();

fn from_str(input: &str) -> Result<NormalizeForm, Self::Err> {
match input {
"NFC" => Ok(NormalizeForm::NFC),
"NFD" => Ok(NormalizeForm::NFD),
"NFKC" => Ok(NormalizeForm::NFKC),
"NFKD" => Ok(NormalizeForm::NFKD),
_ => Err(()),
}
}
}

fn unicode_normalize(s: &str, f: NormalizeForm) -> std::string::String {
match f {
NormalizeForm::NFC => s.nfc().collect::<std::string::String>(),
NormalizeForm::NFD => s.nfd().collect::<std::string::String>(),
NormalizeForm::NFKC => s.nfkc().collect::<std::string::String>(),
NormalizeForm::NFKD => s.nfkd().collect::<std::string::String>(),
}
}
Loading