diff --git a/Libraries/LibJS/Runtime/StringPrototype.cpp b/Libraries/LibJS/Runtime/StringPrototype.cpp index 91787a9fac06b5..3e2deb9c2bde1e 100644 --- a/Libraries/LibJS/Runtime/StringPrototype.cpp +++ b/Libraries/LibJS/Runtime/StringPrototype.cpp @@ -60,6 +60,7 @@ StringPrototype::StringPrototype() put_native_function("concat", concat, 1, attr); put_native_function("substring", substring, 2, attr); put_native_function("includes", includes, 1, attr); + put_native_function("slice", slice, 2, attr); } StringPrototype::~StringPrototype() @@ -399,4 +400,45 @@ Value StringPrototype::includes(Interpreter& interpreter) return Value(substring_search.contains(search_string)); } +Value StringPrototype::slice(Interpreter& interpreter) +{ + auto* string_object = string_object_from(interpreter); + if (!string_object) + return {}; + + auto& string = string_object->primitive_string().string(); + + if (interpreter.argument_count() == 0) + return js_string(interpreter, string); + + i32 string_length = static_cast(string.length()); + i32 index_start = interpreter.argument(0).to_i32(); + i32 index_end = string_length; + + auto negative_min_index = -(string_length - 1); + if (index_start < negative_min_index) + index_start = 0; + else if (index_start < 0) + index_start = string_length + index_start; + + if (interpreter.argument_count() >= 2) { + index_end = interpreter.argument(1).to_i32(); + + if (index_end < negative_min_index) + return js_string(interpreter, String::empty()); + + if (index_end > string_length) + index_end = string_length; + else if (index_end < 0) + index_end = string_length + index_end; + } + + if (index_start >= index_end) + return js_string(interpreter, String::empty()); + + auto part_length = index_end - index_start; + auto string_part = string.substring(index_start, part_length); + return js_string(interpreter, string_part); +} + } diff --git a/Libraries/LibJS/Runtime/StringPrototype.h b/Libraries/LibJS/Runtime/StringPrototype.h index 0b0f54ffb1c53c..df5221df7531f6 100644 --- a/Libraries/LibJS/Runtime/StringPrototype.h +++ b/Libraries/LibJS/Runtime/StringPrototype.h @@ -56,6 +56,7 @@ class StringPrototype final : public StringObject { static Value trim_end(Interpreter&); static Value concat(Interpreter&); static Value includes(Interpreter&); + static Value slice(Interpreter&); }; } diff --git a/Libraries/LibJS/Tests/String.prototype.slice.js b/Libraries/LibJS/Tests/String.prototype.slice.js new file mode 100644 index 00000000000000..a6500ed9d86cca --- /dev/null +++ b/Libraries/LibJS/Tests/String.prototype.slice.js @@ -0,0 +1,22 @@ +load("test-common.js"); + +try { + assert(String.prototype.slice.length === 2); + assert("hello friends".slice() === "hello friends"); + assert("hello friends".slice(1) === "ello friends"); + assert("hello friends".slice(0, 5) === "hello"); + assert("hello friends".slice(13, 6) === ""); + assert("hello friends".slice('', 5) === "hello"); + assert("hello friends".slice(3, 3) === ""); + assert("hello friends".slice(-1, 13) === "s"); + assert("hello friends".slice(0, 50) === "hello friends"); + assert("hello friends".slice(0, "5") === "hello"); + assert("hello friends".slice("6", "13") === "friends"); + assert("hello friends".slice(-7) === "friends"); + assert("hello friends".slice(1000) === ""); + assert("hello friends".slice(-1000) === "hello friends"); + + console.log("PASS"); +} catch (err) { + console.log("FAIL: " + err); +}