mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-22 04:25:13 +00:00
LibWeb/IDB: Implement evaluate_key_path_on_a_value
This commit is contained in:
parent
5ad3db38aa
commit
75fa32d597
2 changed files with 122 additions and 0 deletions
|
@ -14,6 +14,8 @@
|
|||
#include <LibJS/Runtime/TypedArray.h>
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
#include <LibWeb/DOM/EventDispatcher.h>
|
||||
#include <LibWeb/FileAPI/Blob.h>
|
||||
#include <LibWeb/FileAPI/File.h>
|
||||
#include <LibWeb/HTML/EventNames.h>
|
||||
#include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
|
||||
#include <LibWeb/HTML/StructuredSerialize.h>
|
||||
|
@ -855,4 +857,123 @@ WebIDL::ExceptionOr<ErrorOr<GC::Ref<Key>>> convert_a_value_to_a_multi_entry_key(
|
|||
return convert_a_value_to_a_key(realm, value);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/IndexedDB/#evaluate-a-key-path-on-a-value
|
||||
WebIDL::ExceptionOr<ErrorOr<JS::Value>> evaluate_key_path_on_a_value(JS::Realm& realm, JS::Value value, KeyPath const& key_path)
|
||||
{
|
||||
// 1. If keyPath is a list of strings, then:
|
||||
if (key_path.has<Vector<String>>()) {
|
||||
auto const& key_path_list = key_path.get<Vector<String>>();
|
||||
|
||||
// 1. Let result be a new Array object created as if by the expression [].
|
||||
auto result = MUST(JS::Array::create(realm, 0));
|
||||
|
||||
// 2. Let i be 0.
|
||||
u64 i = 0;
|
||||
|
||||
// 3. For each item of keyPath:
|
||||
for (auto const& item : key_path_list) {
|
||||
// 1. Let key be the result of recursively evaluating a key path on a value with item and value.
|
||||
auto completion_key = evaluate_key_path_on_a_value(realm, value, item);
|
||||
|
||||
// 2. Assert: key is not an abrupt completion.
|
||||
VERIFY(!completion_key.is_error());
|
||||
|
||||
// 3. If key is failure, abort the overall algorithm and return failure.
|
||||
auto key = TRY(TRY(completion_key));
|
||||
|
||||
// 4. Let p be ! ToString(i).
|
||||
auto p = JS::PropertyKey { i };
|
||||
|
||||
// 5. Let status be CreateDataProperty(result, p, key).
|
||||
auto status = MUST(result->create_data_property(p, key));
|
||||
|
||||
// 6. Assert: status is true.
|
||||
VERIFY(status);
|
||||
|
||||
// 7. Increase i by 1.
|
||||
i++;
|
||||
}
|
||||
|
||||
// 4. Return result.
|
||||
return result;
|
||||
}
|
||||
|
||||
auto const& key_path_string = key_path.get<String>();
|
||||
|
||||
// 2. If keyPath is the empty string, return value and skip the remaining steps.
|
||||
if (key_path_string.is_empty())
|
||||
return value;
|
||||
|
||||
// 3. Let identifiers be the result of strictly splitting keyPath on U+002E FULL STOP characters (.).
|
||||
// 4. For each identifier of identifiers, jump to the appropriate step below:
|
||||
TRY(key_path_string.bytes_as_string_view().for_each_split_view('.', SplitBehavior::KeepEmpty | SplitBehavior::KeepTrailingSeparator, [&](auto const& identifier) -> ErrorOr<void> {
|
||||
// If Type(value) is String, and identifier is "length"
|
||||
if (value.is_string() && identifier == "length") {
|
||||
// Let value be a Number equal to the number of elements in value.
|
||||
value = JS::Value(value.as_string().utf16_string_view().length_in_code_units());
|
||||
}
|
||||
|
||||
// If value is an Array and identifier is "length"
|
||||
else if (value.is_object() && is<JS::Array>(value.as_object()) && identifier == "length") {
|
||||
// Let value be ! ToLength(! Get(value, "length")).
|
||||
value = JS::Value(MUST(length_of_array_like(realm.vm(), value.as_object())));
|
||||
}
|
||||
|
||||
// If value is a Blob and identifier is "size"
|
||||
else if (value.is_object() && is<FileAPI::Blob>(value.as_object()) && identifier == "size") {
|
||||
// Let value be value’s size.
|
||||
value = JS::Value(static_cast<FileAPI::Blob&>(value.as_object()).size());
|
||||
}
|
||||
|
||||
// If value is a Blob and identifier is "type"
|
||||
else if (value.is_object() && is<FileAPI::Blob>(value.as_object()) && identifier == "type") {
|
||||
// Let value be a String equal to value’s type.
|
||||
value = JS::PrimitiveString::create(realm.vm(), static_cast<FileAPI::Blob&>(value.as_object()).type());
|
||||
}
|
||||
|
||||
// If value is a File and identifier is "name"
|
||||
else if (value.is_object() && is<FileAPI::File>(value.as_object()) && identifier == "name") {
|
||||
// Let value be a String equal to value’s name.
|
||||
value = JS::PrimitiveString::create(realm.vm(), static_cast<FileAPI::File&>(value.as_object()).name());
|
||||
}
|
||||
|
||||
// If value is a File and identifier is "lastModified"
|
||||
else if (value.is_object() && is<FileAPI::File>(value.as_object()) && identifier == "lastModified") {
|
||||
// Let value be a Number equal to value’s lastModified.
|
||||
value = JS::Value(static_cast<double>(static_cast<FileAPI::File&>(value.as_object()).last_modified()));
|
||||
}
|
||||
|
||||
// Otherwise
|
||||
else {
|
||||
// 1. If Type(value) is not Object, return failure.
|
||||
if (!value.is_object())
|
||||
return Error::from_string_literal("Value is not an object");
|
||||
|
||||
auto identifier_property = String::from_utf8_without_validation(identifier.bytes());
|
||||
|
||||
// 2. Let hop be ! HasOwnProperty(value, identifier).
|
||||
auto hop = MUST(value.as_object().has_own_property(identifier_property));
|
||||
|
||||
// 3. If hop is false, return failure.
|
||||
if (!hop)
|
||||
return Error::from_string_literal("Property does not exist");
|
||||
|
||||
// 4. Let value be ! Get(value, identifier).
|
||||
value = MUST(value.as_object().get(identifier_property));
|
||||
|
||||
// 5. If value is undefined, return failure.
|
||||
if (value.is_undefined())
|
||||
return Error::from_string_literal("Value is undefined");
|
||||
}
|
||||
|
||||
return {};
|
||||
}));
|
||||
|
||||
// 5. Assert: value is not an abrupt completion.
|
||||
// NOTE: Step 4 above makes this assertion via MUST
|
||||
|
||||
// 6. Return value.
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,5 +30,6 @@ GC::Ref<HTML::DOMStringList> create_a_sorted_name_list(JS::Realm&, Vector<String
|
|||
void commit_a_transaction(JS::Realm&, GC::Ref<IDBTransaction>);
|
||||
WebIDL::ExceptionOr<JS::Value> clone_in_realm(JS::Realm&, JS::Value, GC::Ref<IDBTransaction>);
|
||||
WebIDL::ExceptionOr<ErrorOr<GC::Ref<Key>>> convert_a_value_to_a_multi_entry_key(JS::Realm&, JS::Value);
|
||||
WebIDL::ExceptionOr<ErrorOr<JS::Value>> evaluate_key_path_on_a_value(JS::Realm&, JS::Value, KeyPath const&);
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue