LibWeb: Implement stubs for XPathEvaluator

This commit is contained in:
Johannes Gustafsson 2025-09-29 21:48:38 +02:00 committed by Jelle Raaijmakers
parent 1ae7ecc3e9
commit f04b866cb0
Notes: github-actions[bot] 2025-10-03 11:17:46 +00:00
17 changed files with 441 additions and 1 deletions

View file

@ -1066,6 +1066,10 @@ set(SOURCES
XHR/XMLHttpRequestUpload.cpp
XLink/AttributeNames.cpp
XML/XMLDocumentBuilder.cpp
XPath/XPathEvaluator.cpp
XPath/XPathExpression.cpp
XPath/XPathNSResolver.cpp
XPath/XPathResult.cpp
)
compile_ipc(Worker/WebWorkerClient.ipc Worker/WebWorkerClientEndpoint.h)

View file

@ -1292,3 +1292,12 @@ class TrustedTypePolicyFactory;
struct TrustedTypePolicyOptions;
}
namespace Web::XPath {
class XPathEvaluator;
class XPathExpression;
class XPathNSResolver;
class XPathResult;
}

View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 2025, Johannes Gustafsson <johannesgu@outlook.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/Realm.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Bindings/PlatformObject.h>
#include <LibWeb/Bindings/XPathEvaluatorPrototype.h>
#include <LibWeb/WebIDL/ExceptionOr.h>
#include "XPathEvaluator.h"
#include "XPathExpression.h"
#include "XPathResult.h"
namespace Web::XPath {
GC_DEFINE_ALLOCATOR(XPathEvaluator);
XPathEvaluator::XPathEvaluator(JS::Realm& realm)
: Web::Bindings::PlatformObject(realm)
{
}
XPathEvaluator::~XPathEvaluator() = default;
WebIDL::ExceptionOr<GC::Ref<XPathEvaluator>> XPathEvaluator::construct_impl(JS::Realm& realm)
{
return realm.create<XPathEvaluator>(realm);
}
void XPathEvaluator::initialize(JS::Realm& realm)
{
WEB_SET_PROTOTYPE_FOR_INTERFACE(XPathEvaluator);
Base::initialize(realm);
}
WebIDL::ExceptionOr<GC::Ref<XPathExpression>> XPathEvaluator::create_expression(String const& expression, GC::Ptr<XPathNSResolver> resolver)
{
auto& realm = this->realm();
return realm.create<XPathExpression>(realm, expression, resolver);
}
WebIDL::ExceptionOr<GC::Ref<XPathResult>> XPathEvaluator::evaluate(String const&, DOM::Node const&, GC::Ptr<XPathNSResolver>, WebIDL::UnsignedShort, GC::Ptr<XPathResult>)
{
auto& realm = this->realm();
return realm.create<XPathResult>(realm);
}
GC::Ref<DOM::Node> XPathEvaluator::create_ns_resolver(GC::Ref<DOM::Node> node_resolver)
{
return node_resolver;
}
}

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2025, Johannes Gustafsson <johannesgu@outlook.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibWeb/Bindings/PlatformObject.h>
#include <LibWeb/Forward.h>
#include <LibWeb/WebIDL/Types.h>
#include "XPathExpression.h"
#include "XPathNSResolver.h"
#include "XPathResult.h"
namespace Web::XPath {
class XPathEvaluator : public Bindings::PlatformObject {
WEB_PLATFORM_OBJECT(XPathEvaluator, Bindings::PlatformObject);
GC_DECLARE_ALLOCATOR(XPathEvaluator);
explicit XPathEvaluator(JS::Realm&);
virtual ~XPathEvaluator() override;
public:
static WebIDL::ExceptionOr<GC::Ref<XPathEvaluator>> construct_impl(JS::Realm&);
virtual void initialize(JS::Realm&) override;
WebIDL::ExceptionOr<GC::Ref<XPathExpression>> create_expression(String const& expression, GC::Ptr<XPathNSResolver> resolver = nullptr);
WebIDL::ExceptionOr<GC::Ref<XPathResult>> evaluate(String const& expression, DOM::Node const& context_node, GC::Ptr<XPathNSResolver> resolver = nullptr, WebIDL::UnsignedShort type = 0, GC::Ptr<XPathResult> result = nullptr);
static GC::Ref<DOM::Node> create_ns_resolver(GC::Ref<DOM::Node> node_resolver); // legacy
};
}

View file

@ -0,0 +1,24 @@
#import <DOM/Node.idl>
// FIXME: callback interfaces are not currently supported
// callback interface XPathNSResolver {
// DOMString? lookupNamespaceURI(DOMString? prefix);
// };
// https://dom.spec.whatwg.org/#mixin-xpathevaluatorbase
interface mixin XPathEvaluatorBase {
[NewObject] XPathExpression createExpression(DOMString expression, optional XPathNSResolver? resolver = null);
Node createNSResolver(Node nodeResolver); // legacy
// XPathResult.ANY_TYPE = 0
XPathResult evaluate(DOMString expression, Node contextNode, optional XPathNSResolver? resolver = null, optional unsigned short type = 0, optional XPathResult? result = null);
};
Document includes XPathEvaluatorBase;
// https://dom.spec.whatwg.org/#interface-xpathevaluator
[Exposed=Window]
interface XPathEvaluator {
constructor();
};
XPathEvaluator includes XPathEvaluatorBase;

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2025, Johannes Gustafsson <johannesgu@outlook.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/Realm.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Bindings/PlatformObject.h>
#include <LibWeb/Bindings/XPathExpressionPrototype.h>
#include <LibWeb/DOM/Node.h>
#include <LibWeb/Forward.h>
#include "XPathEvaluator.h"
#include "XPathExpression.h"
#include "XPathResult.h"
namespace Web::XPath {
GC_DEFINE_ALLOCATOR(XPathExpression);
XPathExpression::XPathExpression(JS::Realm& realm, String const& expression, GC::Ptr<XPathNSResolver> resolver)
: Web::Bindings::PlatformObject(realm)
, m_expression(expression)
, m_resolver(resolver)
{
}
void XPathExpression::initialize(JS::Realm& realm)
{
WEB_SET_PROTOTYPE_FOR_INTERFACE(XPathExpression);
Base::initialize(realm);
}
void XPathExpression::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_resolver);
}
XPathExpression::~XPathExpression() = default;
WebIDL::ExceptionOr<GC::Ref<XPathResult>> XPathExpression::evaluate(DOM::Node const&, WebIDL::UnsignedShort, GC::Ptr<XPathResult>)
{
auto& realm = this->realm();
return realm.create<XPathResult>(realm);
}
}

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2025, Johannes Gustafsson <johannesgu@outlook.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibWeb/Bindings/PlatformObject.h>
#include <LibWeb/Forward.h>
#include <LibWeb/WebIDL/Types.h>
#include "XPathResult.h"
namespace Web::XPath {
class XPathExpression final : public Bindings::PlatformObject {
WEB_PLATFORM_OBJECT(XPathExpression, Bindings::PlatformObject);
GC_DECLARE_ALLOCATOR(XPathExpression);
public:
explicit XPathExpression(JS::Realm&, String const& expression, GC::Ptr<XPathNSResolver> resolver);
virtual ~XPathExpression() override;
virtual void visit_edges(Cell::Visitor&) override;
virtual void initialize(JS::Realm&) override;
WebIDL::ExceptionOr<GC::Ref<XPathResult>> evaluate(DOM::Node const& context_node, WebIDL::UnsignedShort type = 0, GC::Ptr<XPathResult> result = nullptr);
private:
String m_expression;
GC::Ptr<XPathNSResolver> m_resolver;
};
}

View file

@ -0,0 +1,9 @@
#import <XPath/XPathResult.idl>
// https://dom.spec.whatwg.org/#interface-xpathexpression
[Exposed=Window]
interface XPathExpression {
// XPathResult.ANY_TYPE = 0
XPathResult evaluate(Node contextNode, optional unsigned short type = 0, optional XPathResult? result = null);
};

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2025, Johannes Gustafsson <johannesgu@outlook.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/Object.h>
#include <LibJS/Runtime/Realm.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/WebIDL/CallbackType.h>
#include "XPathNSResolver.h"
namespace Web::XPath {
GC_DEFINE_ALLOCATOR(XPathNSResolver);
GC::Ref<XPathNSResolver> XPathNSResolver::create(JS::Realm& realm, GC::Ref<WebIDL::CallbackType> callback)
{
return realm.create<XPathNSResolver>(realm, callback);
}
XPathNSResolver::XPathNSResolver(JS::Realm& realm, GC::Ref<WebIDL::CallbackType> callback)
: JS::Object(ConstructWithPrototypeTag::Tag, realm.intrinsics().object_prototype())
, m_callback(callback)
{
}
void XPathNSResolver::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_callback);
}
}

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2025, Johannes Gustafsson <johannesgu@outlook.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibWeb/Bindings/PlatformObject.h>
#include <LibWeb/Forward.h>
#include "XPathResult.h"
namespace Web::XPath {
class XPathNSResolver final : public JS::Object {
JS_OBJECT(XPathNSResolver, JS::Object);
GC_DECLARE_ALLOCATOR(XPathNSResolver);
public:
[[nodiscard]] static GC::Ref<XPathNSResolver> create(JS::Realm&, GC::Ref<WebIDL::CallbackType>);
XPathNSResolver(JS::Realm&, GC::Ref<WebIDL::CallbackType>);
virtual ~XPathNSResolver() = default;
virtual void visit_edges(Cell::Visitor&) override;
private:
GC::Ref<WebIDL::CallbackType> m_callback;
};
}

View file

@ -0,0 +1,55 @@
/*
* Copyright (c) 2025, Johannes Gustafsson <johannesgu@outlook.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/Realm.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Bindings/PlatformObject.h>
#include <LibWeb/Bindings/XPathResultPrototype.h>
#include <LibWeb/DOM/Node.h>
#include "XPathResult.h"
namespace Web::XPath {
GC_DEFINE_ALLOCATOR(XPathResult);
XPathResult::XPathResult(JS::Realm& realm)
: Web::Bindings::PlatformObject(realm)
{
m_node_set_iter = m_node_set.end();
}
void XPathResult::initialize(JS::Realm& realm)
{
WEB_SET_PROTOTYPE_FOR_INTERFACE(XPathResult);
Base::initialize(realm);
}
void XPathResult::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_node_set);
}
XPathResult::~XPathResult() = default;
GC::Ptr<DOM::Node> XPathResult::iterate_next()
{
if (m_node_set_iter == m_node_set.end())
return nullptr;
return *m_node_set_iter++;
}
GC::Ptr<DOM::Node> XPathResult::snapshot_item(int index)
{
if (index < 0 || static_cast<size_t>(index) >= m_node_set.size())
return nullptr;
return m_node_set.at(index);
}
}

View file

@ -0,0 +1,61 @@
/*
* Copyright (c) 2025, Johannes Gustafsson <johannesgu@outlook.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/String.h>
#include <AK/Vector.h>
#include <LibWeb/Bindings/PlatformObject.h>
#include <LibWeb/Forward.h>
#include <LibWeb/WebIDL/Types.h>
namespace Web::XPath {
class XPathResult : public Bindings::PlatformObject {
WEB_PLATFORM_OBJECT(XPathResult, Bindings::PlatformObject);
GC_DECLARE_ALLOCATOR(XPathResult);
public:
static WebIDL::UnsignedShort const ANY_TYPE = 0;
static WebIDL::UnsignedShort const NUMBER_TYPE = 1;
static WebIDL::UnsignedShort const STRING_TYPE = 2;
static WebIDL::UnsignedShort const BOOLEAN_TYPE = 3;
static WebIDL::UnsignedShort const UNORDERED_NODE_ITERATOR_TYPE = 4;
static WebIDL::UnsignedShort const ORDERED_NODE_ITERATOR_TYPE = 5;
static WebIDL::UnsignedShort const UNORDERED_NODE_SNAPSHOT_TYPE = 6;
static WebIDL::UnsignedShort const ORDERED_NODE_SNAPSHOT_TYPE = 7;
static WebIDL::UnsignedShort const ANY_UNORDERED_NODE_TYPE = 8;
static WebIDL::UnsignedShort const FIRST_ORDERED_NODE_TYPE = 9;
XPathResult(JS::Realm&);
virtual ~XPathResult() override;
virtual void initialize(JS::Realm&) override;
virtual void visit_edges(Cell::Visitor&) override;
WebIDL::UnsignedShort result_type() const { return m_result_type; }
WebIDL::Double number_value() const { return m_number_value; }
String string_value() { return m_string_value; }
WebIDL::Boolean boolean_value() const { return m_boolean_value; }
GC::Ptr<DOM::Node> single_node_value() { return m_node_set.is_empty() ? nullptr : m_node_set.first(); }
WebIDL::Boolean invalid_iterator_state() const { return m_invalid_iterator_state; }
WebIDL::UnsignedLong snapshot_length() const { return m_node_set.size(); }
GC::Ptr<DOM::Node> iterate_next();
GC::Ptr<DOM::Node> snapshot_item(int index);
private:
WebIDL::UnsignedShort m_result_type;
WebIDL::Double m_number_value;
String m_string_value;
WebIDL::Boolean m_boolean_value;
WebIDL::Boolean m_invalid_iterator_state;
WebIDL::UnsignedLong m_snapshot_length;
Vector<GC::Ptr<DOM::Node>> m_node_set;
Vector<GC::Ptr<DOM::Node>>::Iterator m_node_set_iter;
};
}

View file

@ -0,0 +1,29 @@
#import <DOM/Node.idl>
// https://dom.spec.whatwg.org/#interface-xpathresult
[Exposed=Window]
interface XPathResult {
const unsigned short ANY_TYPE = 0;
const unsigned short NUMBER_TYPE = 1;
const unsigned short STRING_TYPE = 2;
const unsigned short BOOLEAN_TYPE = 3;
const unsigned short UNORDERED_NODE_ITERATOR_TYPE = 4;
const unsigned short ORDERED_NODE_ITERATOR_TYPE = 5;
const unsigned short UNORDERED_NODE_SNAPSHOT_TYPE = 6;
const unsigned short ORDERED_NODE_SNAPSHOT_TYPE = 7;
const unsigned short ANY_UNORDERED_NODE_TYPE = 8;
const unsigned short FIRST_ORDERED_NODE_TYPE = 9;
readonly attribute unsigned short resultType;
readonly attribute unrestricted double numberValue;
readonly attribute DOMString stringValue;
readonly attribute boolean booleanValue;
readonly attribute Node? singleNodeValue;
readonly attribute boolean invalidIteratorState;
readonly attribute unsigned long snapshotLength;
Node? iterateNext();
Node? snapshotItem(unsigned long index);
};

View file

@ -502,3 +502,6 @@ libweb_js_bindings(XHR/ProgressEvent)
libweb_js_bindings(XHR/XMLHttpRequest)
libweb_js_bindings(XHR/XMLHttpRequestEventTarget)
libweb_js_bindings(XHR/XMLHttpRequestUpload)
libweb_js_bindings(XPath/XPathResult)
libweb_js_bindings(XPath/XPathExpression)
libweb_js_bindings(XPath/XPathEvaluator)

View file

@ -160,6 +160,7 @@ static bool is_platform_object(Type const& type)
"Window"sv,
"WindowProxy"sv,
"WritableStream"sv,
"XPathResult"sv,
};
if (type.name().ends_with("Element"sv))
return true;
@ -681,7 +682,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
generate_to_string(scoped_generator, parameter, variadic, optional, optional_default_value);
} else if (parameter.type->is_boolean() || parameter.type->is_integer()) {
generate_to_integral(scoped_generator, parameter, optional, optional_default_value);
} else if (parameter.type->name().is_one_of("EventListener", "NodeFilter")) {
} else if (parameter.type->name().is_one_of("EventListener", "NodeFilter", "XPathNSResolver")) {
// FIXME: Replace this with support for callback interfaces. https://webidl.spec.whatwg.org/#idl-callback-interface
if (parameter.type->name() == "EventListener")
@ -4973,6 +4974,7 @@ using namespace Web::WebGL::Extensions;
using namespace Web::WebIDL;
using namespace Web::WebVTT;
using namespace Web::XHR;
using namespace Web::XPath;
)~~~"sv);
}

View file

@ -49,6 +49,7 @@ static constexpr Array libweb_interface_namespaces = {
"WebIDL"sv,
"WebSockets"sv,
"XHR"sv,
"XPath"sv,
};
}

View file

@ -525,6 +525,9 @@ XMLHttpRequest
XMLHttpRequestEventTarget
XMLHttpRequestUpload
XMLSerializer
XPathEvaluator
XPathExpression
XPathResult
__finishTest
__preventMultipleTestFunctions
animationFrame