srctree

Robin Linden parent 7ac90ad9 b976c932
dom2: Remove stale beginning of a spec-compliant dom implementation

This hasn't really been touched since it was stubbed out in 2021 exceptfor clang-tidy warnings being fixed as they're enabled.

I don't think I'd implement this the same way if I were to start ittoday, but even if we were to decide we love this old design, it's justone revert away.

inlinesplit
.clang-tidy added: 27, removed: 947, total 0
@@ -76,7 +76,7 @@ Checks: >
# clang-tidy-16.
WarningsAsErrors: "*,-clang-diagnostic-builtin-macro-redefined"
 
HeaderFilterRegex: "\\./(archive|azm|browser|css|css2|dom|dom2|engine|etest|geom|gfx|html|html2|idna|img|js|layout|net|os|protocol|render|style|tui|type|uri|url|util|wasm)/"
HeaderFilterRegex: "\\./(archive|azm|browser|css|css2|dom|engine|etest|geom|gfx|html|html2|idna|img|js|layout|net|os|protocol|render|style|tui|type|uri|url|util|wasm)/"
 
CheckOptions:
# performance-move-const-arg
 
ev/null added: 27, removed: 947, total 0
@@ -1,24 +0,0 @@
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
load("//bzl:copts.bzl", "HASTUR_COPTS")
 
cc_library(
name = "dom2",
srcs = glob(
include = ["*.cpp"],
exclude = ["*_test.cpp"],
),
hdrs = glob(["*.h"]),
copts = HASTUR_COPTS,
visibility = ["//visibility:public"],
)
 
[cc_test(
name = src[:-4],
size = "small",
srcs = [src],
copts = HASTUR_COPTS,
deps = [
":dom2",
"//etest",
],
) for src in glob(["*_test.cpp"])]
 
ev/null added: 27, removed: 947, total 0
@@ -1,20 +0,0 @@
// SPDX-FileCopyrightText: 2021 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#ifndef DOM2_ATTR_H_
#define DOM2_ATTR_H_
 
#include "dom2/node.h"
 
namespace dom2 {
 
// https://dom.spec.whatwg.org/#interface-attr
class Attr final : public Node {
public:
[[nodiscard]] NodeType type() const override { return NodeType::Attribute; }
};
 
} // namespace dom2
 
#endif
 
ev/null added: 27, removed: 947, total 0
@@ -1,20 +0,0 @@
// SPDX-FileCopyrightText: 2021 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#include "dom2/attr.h"
 
#include "etest/etest.h"
 
using etest::expect_eq;
 
using namespace dom2;
 
int main() {
etest::test("type", [] {
Attr node{};
expect_eq(node.type(), NodeType::Attribute);
});
 
return etest::run_all_tests();
}
 
ev/null added: 27, removed: 947, total 0
@@ -1,20 +0,0 @@
// SPDX-FileCopyrightText: 2021 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#ifndef DOM2_CDATA_SECTION_H_
#define DOM2_CDATA_SECTION_H_
 
#include "dom2/text.h"
 
namespace dom2 {
 
// https://dom.spec.whatwg.org/#interface-cdatasection
class CdataSection final : public Text {
public:
[[nodiscard]] NodeType type() const override { return NodeType::CdataSection; }
};
 
} // namespace dom2
 
#endif
 
ev/null added: 27, removed: 947, total 0
@@ -1,20 +0,0 @@
// SPDX-FileCopyrightText: 2021 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#include "dom2/cdata_section.h"
 
#include "etest/etest.h"
 
using etest::expect_eq;
 
using namespace dom2;
 
int main() {
etest::test("type", [] {
CdataSection node{};
expect_eq(node.type(), NodeType::CdataSection);
});
 
return etest::run_all_tests();
}
 
ev/null added: 27, removed: 947, total 0
@@ -1,93 +0,0 @@
// SPDX-FileCopyrightText: 2021 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#ifndef DOM2_CHARACTER_DATA_H_
#define DOM2_CHARACTER_DATA_H_
 
#include "dom2/node.h"
 
#include <cstddef>
#include <exception>
#include <string>
#include <string_view>
#include <utility>
 
namespace dom2 {
 
// https://dom.spec.whatwg.org/#interface-characterdata
// TODO(robinlinden): The spec wants the strings to be 16-bit integers.
class CharacterData : public Node {
protected:
explicit CharacterData(std::string data) : data_{std::move(data)} {}
 
public:
[[nodiscard]] std::string const &data() const { return data_; }
[[nodiscard]] std::size_t length() const { return data_.length(); }
 
[[nodiscard]] std::string substring_data(std::size_t offset, std::size_t count) const {
if (offset > length()) {
// TODO(robinlinden): then throw an "IndexSizeError" DOMException.
std::terminate();
}
 
return data().substr(offset, count);
}
 
void append_data(std::string_view data) { replace_data(length(), 0, data); }
void insert_data(std::size_t offset, std::string_view data) { replace_data(offset, 0, data); }
void delete_data(std::size_t offset, std::size_t count) { replace_data(offset, count, std::string_view{""}); }
 
// https://dom.spec.whatwg.org/#concept-cd-replace
// TODO(robinlinden): Mutation record, live range, and children changed stuff.
void replace_data(std::size_t offset, std::size_t count, std::string_view data) {
// Let length be node's length.
// If offset is greater than length, then throw an "IndexSizeError" DOMException.
if (offset > length()) {
// TODO(robinlinden): then throw an "IndexSizeError" DOMException.
std::terminate();
}
 
// If offset plus count is greater than length, then set count to length minus offset.
if (offset + count > length()) {
count = length() - offset;
}
 
// Queue a mutation record of "characterData" for node with null, null,
// node's data, « », « », null, and null.
 
// Insert data into node's data after offset code units.
data_.insert(offset, data);
 
// Let delete offset be offset + data's length.
std::size_t delete_offset = offset + data.length();
 
// Starting from delete offset code units, remove count code units from node's data.
data_.erase(delete_offset, count);
 
// For each live range whose start node is node and start offset is
// greater than offset but less than or equal to offset plus count, set
// its start offset to offset.
 
// For each live range whose end node is node and end offset is greater
// than offset but less than or equal to offset plus count, set its end
// offset to offset.
 
// For each live range whose start node is node and start offset is
// greater than offset plus count, increase its start offset by data's
// length and decrease it by count.
 
// For each live range whose end node is node and end offset is greater
// than offset plus count, increase its end offset by data's length and
// decrease it by count.
 
// If node's parent is non-null, then run the children changed steps for node's parent.
}
 
private:
std::string data_{};
};
 
} // namespace dom2
 
#endif
 
ev/null added: 27, removed: 947, total 0
@@ -1,88 +0,0 @@
// SPDX-FileCopyrightText: 2021 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#include "dom2/character_data.h"
 
#include "etest/etest.h"
 
#include <cstddef>
#include <string>
#include <string_view>
#include <utility>
 
using namespace std::literals;
using etest::expect_eq;
 
using namespace dom2;
 
namespace {
 
class TestableCharacterData : public CharacterData {
public:
explicit TestableCharacterData(std::string data = ""s) : CharacterData(std::move(data)) {}
 
// Not correct, but let's pretend this is fine so I can test the rest of the methods.
NodeType type() const override { return NodeType::Text; }
};
 
} // namespace
 
int main() {
etest::test("construction", [] {
TestableCharacterData data{};
expect_eq(data.data(), ""sv);
expect_eq(data.length(), static_cast<std::size_t>(0));
 
auto ohno = "oh no"s;
data = TestableCharacterData{ohno};
expect_eq(data.data(), ohno);
expect_eq(data.length(), ohno.length());
});
 
etest::test("substring_data", [] {
TestableCharacterData data{};
expect_eq(data.substring_data(0, 0), ""sv);
expect_eq(data.substring_data(0, 10), ""sv);
 
data = TestableCharacterData{"oh no"s};
expect_eq(data.substring_data(0, 100), "oh no"sv);
expect_eq(data.substring_data(1, 100), "h no"sv);
expect_eq(data.substring_data(1, 3), "h n"sv);
});
 
etest::test("append_data", [] {
TestableCharacterData data{};
data.append_data("test"sv);
expect_eq(data.data(), "test"sv);
data.append_data("y test"sv);
expect_eq(data.data(), "testy test"sv);
});
 
etest::test("insert_data", [] {
TestableCharacterData data{};
data.insert_data(0, "test"sv);
expect_eq(data.data(), "test"sv);
data.insert_data(4, "ed"sv);
data.insert_data(0, "very "sv);
expect_eq(data.data(), "very tested"sv);
});
 
etest::test("delete_data", [] {
TestableCharacterData data{"hello world"s};
data.delete_data(5, 100);
expect_eq(data.data(), "hello"sv);
data.delete_data(0, 1);
expect_eq(data.data(), "ello"sv);
});
 
etest::test("replace_data", [] {
TestableCharacterData data{};
data.replace_data(0, 0, "hello"sv);
expect_eq(data.data(), "hello"sv);
data.replace_data(4, 1, ""sv);
expect_eq(data.data(), "hell"sv);
});
 
return etest::run_all_tests();
}
 
ev/null added: 27, removed: 947, total 0
@@ -1,25 +0,0 @@
// SPDX-FileCopyrightText: 2021 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#ifndef DOM2_COMMENT_H_
#define DOM2_COMMENT_H_
 
#include "dom2/character_data.h"
 
#include <string>
#include <utility>
 
namespace dom2 {
 
// https://dom.spec.whatwg.org/#interface-comment
class Comment final : public CharacterData {
public:
explicit Comment(std::string data = std::string{""}) : CharacterData(std::move(data)) {}
 
[[nodiscard]] NodeType type() const override { return NodeType::Comment; }
};
 
} // namespace dom2
 
#endif
 
ev/null added: 27, removed: 947, total 0
@@ -1,30 +0,0 @@
// SPDX-FileCopyrightText: 2021 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#include "dom2/comment.h"
 
#include "etest/etest.h"
 
#include <string_view>
 
using namespace std::literals;
using etest::expect_eq;
 
using namespace dom2;
 
int main() {
etest::test("construction", [] {
Comment node{};
expect_eq(node.data(), ""sv);
node = Comment{"comment"};
expect_eq(node.data(), "comment"sv);
});
 
etest::test("type", [] {
Comment node{};
expect_eq(node.type(), NodeType::Comment);
});
 
return etest::run_all_tests();
}
 
ev/null added: 27, removed: 947, total 0
@@ -1,20 +0,0 @@
// SPDX-FileCopyrightText: 2021 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#ifndef DOM2_DOCUMENT_H_
#define DOM2_DOCUMENT_H_
 
#include "dom2/node.h"
 
namespace dom2 {
 
// https://dom.spec.whatwg.org/#interface-document
class Document final : public Node {
public:
[[nodiscard]] NodeType type() const override { return NodeType::Document; }
};
 
} // namespace dom2
 
#endif
 
ev/null added: 27, removed: 947, total 0
@@ -1,20 +0,0 @@
// SPDX-FileCopyrightText: 2021 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#ifndef DOM2_DOCUMENT_FRAGMENT_H_
#define DOM2_DOCUMENT_FRAGMENT_H_
 
#include "dom2/node.h"
 
namespace dom2 {
 
// https://dom.spec.whatwg.org/#interface-documentfragment
class DocumentFragment : public Node {
public:
[[nodiscard]] NodeType type() const final { return NodeType::DocumentFragment; }
};
 
} // namespace dom2
 
#endif
 
ev/null added: 27, removed: 947, total 0
@@ -1,20 +0,0 @@
// SPDX-FileCopyrightText: 2021 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#include "dom2/document_fragment.h"
 
#include "etest/etest.h"
 
using etest::expect_eq;
 
using namespace dom2;
 
int main() {
etest::test("type", [] {
DocumentFragment node{};
expect_eq(node.type(), NodeType::DocumentFragment);
});
 
return etest::run_all_tests();
}
 
ev/null added: 27, removed: 947, total 0
@@ -1,20 +0,0 @@
// SPDX-FileCopyrightText: 2021 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#include "dom2/document.h"
 
#include "etest/etest.h"
 
using etest::expect_eq;
 
using namespace dom2;
 
int main() {
etest::test("type", [] {
Document node{};
expect_eq(node.type(), NodeType::Document);
});
 
return etest::run_all_tests();
}
 
ev/null added: 27, removed: 947, total 0
@@ -1,36 +0,0 @@
// SPDX-FileCopyrightText: 2021 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#ifndef DOM2_DOCUMENT_TYPE_H_
#define DOM2_DOCUMENT_TYPE_H_
 
#include "dom2/node.h"
 
#include <string>
#include <utility>
 
namespace dom2 {
 
// https://dom.spec.whatwg.org/#interface-documenttype
class DocumentType final : public Node {
public:
explicit DocumentType(
std::string name, std::string public_id = std::string{""}, std::string system_id = std::string{""})
: name_{std::move(name)}, public_id_{std::move(public_id)}, system_id_{std::move(system_id)} {}
 
[[nodiscard]] NodeType type() const override { return NodeType::DocumentType; }
 
[[nodiscard]] std::string const &name() const { return name_; }
[[nodiscard]] std::string const &public_id() const { return public_id_; }
[[nodiscard]] std::string const &system_id() const { return system_id_; }
 
private:
std::string name_{};
std::string public_id_{};
std::string system_id_{};
};
 
} // namespace dom2
 
#endif
 
ev/null added: 27, removed: 947, total 0
@@ -1,42 +0,0 @@
// SPDX-FileCopyrightText: 2021 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#include "dom2/document_type.h"
 
#include "etest/etest.h"
 
#include <string>
#include <string_view>
 
using namespace std::literals;
using etest::expect;
using etest::expect_eq;
 
using namespace dom2;
 
int main() {
etest::test("type", [] {
DocumentType node{"html"s};
expect_eq(node.type(), NodeType::DocumentType);
});
 
etest::test("construction", [] {
DocumentType node{"html"s};
expect_eq(node.name(), "html"sv);
expect(node.public_id().empty());
expect(node.system_id().empty());
 
DocumentType node_with_public_id{"good name"s, "some id"s};
expect_eq(node_with_public_id.name(), "good name"sv);
expect_eq(node_with_public_id.public_id(), "some id"sv);
expect(node_with_public_id.system_id().empty());
 
DocumentType node_with_public_and_system_id{"good name"s, "some id"s, "another id"};
expect_eq(node_with_public_and_system_id.name(), "good name"sv);
expect_eq(node_with_public_and_system_id.public_id(), "some id"sv);
expect_eq(node_with_public_and_system_id.system_id(), "another id"sv);
});
 
return etest::run_all_tests();
}
 
ev/null added: 27, removed: 947, total 0
@@ -1,31 +0,0 @@
// SPDX-FileCopyrightText: 2021 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#ifndef DOM2_ELEMENT_H_
#define DOM2_ELEMENT_H_
 
#include "dom2/node.h"
 
#include <string>
#include <utility>
 
namespace dom2 {
 
// https://dom.spec.whatwg.org/#interface-element
// TODO(robinlinden): This is only partially implemented.
class Element final : public Node {
public:
explicit Element(std::string local_name) : local_name_{std::move(local_name)} {}
 
[[nodiscard]] NodeType type() const override { return NodeType::Element; }
 
[[nodiscard]] std::string const &local_name() const { return local_name_; }
 
private:
std::string local_name_{};
};
 
} // namespace dom2
 
#endif
 
ev/null added: 27, removed: 947, total 0
@@ -1,28 +0,0 @@
// SPDX-FileCopyrightText: 2021 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#include "dom2/element.h"
 
#include "etest/etest.h"
 
#include <string>
 
using namespace std::literals;
using etest::expect_eq;
 
using namespace dom2;
 
int main() {
etest::test("type", [] {
Element node{"a"s};
expect_eq(node.type(), NodeType::Element);
});
 
etest::test("local name", [] {
Element node{"title"s};
expect_eq(node.local_name(), "title");
});
 
return etest::run_all_tests();
}
 
ev/null added: 27, removed: 947, total 0
@@ -1,110 +0,0 @@
// SPDX-FileCopyrightText: 2021 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#include "dom2/node.h"
 
#include <exception>
#include <utility>
 
namespace dom2 {
 
// https://dom.spec.whatwg.org/#concept-node-append
std::shared_ptr<Node> Node::append_child(std::shared_ptr<Node> child) {
// To append a node to a parent, pre-insert node into parent before null.
return pre_insert(std::move(child), nullptr);
}
 
// https://dom.spec.whatwg.org/#concept-node-pre-insert
std::shared_ptr<Node> Node::pre_insert(std::shared_ptr<Node> node, Node const *child) {
// 1. Ensure pre-insertion validity of node into parent before child.
// TODO(robinlinden): Ensure pre-insertion validity.
 
// 2. Let referenceChild be child.
auto const *reference_child = child;
 
// 3. If referenceChild is node, then set referenceChild to node's next sibling.
if (reference_child == node.get()) {
reference_child = node->next_sibling();
}
 
// 4. Insert node into parent before referenceChild.
insert(node, reference_child);
 
// 5. Return node.
return node;
}
 
// https://dom.spec.whatwg.org/#concept-node-insert
void Node::insert(std::shared_ptr<Node> const &node, Node const *child, [[maybe_unused]] bool suppress_observers) {
// 1. Let nodes be node's children, if node is a DocumentFragment node; otherwise « node ».
auto const &nodes =
node->type() == NodeType::DocumentFragment ? node->child_nodes() : std::vector<std::shared_ptr<Node>>{node};
 
// 2. Let count be nodes's size.
auto count = nodes.size();
 
// 3. If count is 0, then return.
if (count == 0) {
return;
}
 
// 4. If node is a DocumentFragment node, then:
if (node->type() == NodeType::DocumentFragment) {
// 1. Remove its children with the suppress observers flag set.
// 2. Queue a tree mutation record for node with « », nodes, null, and null.
// Note: This step intentionally does not pay attention to the suppress observers flag.
std::terminate();
}
 
// 5. If child is non-null, then:
if (child != nullptr) {
// 1. For each live range whose start node is parent and start offset is greater than child's index, increase
// its start offset by count.
// 2. For each live range whose end node is parent and end offset is greater than child's index, increase its
// end offset by count.
std::terminate();
}
 
// 6. Let previousSibling be child's previous sibling or parent's last child if child is null.
[[maybe_unused]] Node const *previous_sibling = child != nullptr ? child->previous_sibling() : last_child();
 
// 7. For each node in nodes, in tree order:
for (auto const &n : nodes) {
// TODO(robinlinden):
// 1. Adopt node into parent's node document.
 
// 2. If child is null, then append node to parent's children.
// 3. Otherwise, insert node into parent's children before child's index.
if (child == nullptr) {
child_nodes_.push_back(n);
} else {
std::terminate();
}
 
// Please keep my indented comments, clang-format. It looks silly, but they go where blocks will go.
// clang-format off
// TODO(robinlinden):
// 4. If parent is a shadow host whose shadow root's slot assignment is "named" and node is a slottable, then
// assign a slot for node.
// 5. If parent's root is a shadow root, and parent is a slot whose assigned nodes is the empty list, then run
// signal a slot change for parent.
// 6. Run assign slottables for a tree with node's root.
// 7. For each shadow-including inclusive descendant inclusiveDescendant of node, in shadow-including tree
// order:
// 1. Run the insertion steps with inclusiveDescendant.
// 2. If inclusiveDescendant is connected, then:
// 1. If inclusiveDescendant is custom, then enqueue a custom element callback reaction with
// inclusiveDescendant, callback name "connectedCallback", and an empty argument list.
// 2. Otherwise, try to upgrade inclusiveDescendant.
// Note: If this successfully upgrades inclusiveDescendant, its connectedCallback will be enqueued
// automatically during the upgrade an element algorithm.
}
 
// TODO(robinlinden):
// 8. If suppress observers flag is unset, then queue a tree mutation record for parent with nodes, « »,
// previousSibling, and child.
// 9. Run the children changed steps for parent.
}
 
} // namespace dom2
 
ev/null added: 27, removed: 947, total 0
@@ -1,61 +0,0 @@
// SPDX-FileCopyrightText: 2021 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#ifndef DOM2_NODE_H_
#define DOM2_NODE_H_
 
#include <cstdint>
#include <exception>
#include <memory>
#include <vector>
 
namespace dom2 {
 
enum class NodeType : std::uint16_t {
Element = 1,
Attribute = 2,
Text = 3,
CdataSection = 4,
EntityReference = 5,
Entity = 6,
ProcessingInstruction = 7,
Comment = 8,
Document = 9,
DocumentType = 10,
DocumentFragment = 11,
Notation = 12,
};
 
// https://dom.spec.whatwg.org/#interface-node
class Node {
public:
virtual ~Node() = default;
 
[[nodiscard]] virtual NodeType type() const = 0;
 
[[nodiscard]] bool has_child_nodes() const { return !child_nodes_.empty(); }
[[nodiscard]] std::vector<std::shared_ptr<Node>> const &child_nodes() const { return child_nodes_; }
[[nodiscard]] Node const *first_child() const {
return child_nodes().empty() ? nullptr : child_nodes().front().get();
}
[[nodiscard]] Node const *last_child() const {
return child_nodes().empty() ? nullptr : child_nodes().back().get();
}
[[nodiscard]] Node const *previous_sibling() const { std::terminate(); }
[[nodiscard]] Node const *next_sibling() const { std::terminate(); }
 
std::shared_ptr<Node> append_child(std::shared_ptr<Node> child);
 
[[nodiscard]] bool operator==(Node const &) const = default;
 
private:
std::vector<std::shared_ptr<Node>> child_nodes_{};
 
std::shared_ptr<Node> pre_insert(std::shared_ptr<Node> node, Node const *child);
void insert(std::shared_ptr<Node> const &node, Node const *child, bool suppress_observers = false);
};
 
} // namespace dom2
 
#endif
 
ev/null added: 27, removed: 947, total 0
@@ -1,72 +0,0 @@
// SPDX-FileCopyrightText: 2021 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#include "dom2/node.h"
 
#include "etest/etest.h"
 
using namespace std::literals;
using etest::expect;
using etest::expect_eq;
using etest::require;
 
using namespace dom2;
 
namespace {
struct TestNode final : Node {
explicit TestNode(NodeType type) : type_{type} {}
[[nodiscard]] NodeType type() const override { return type_; }
 
private:
NodeType type_;
};
} // namespace
 
int main() {
etest::test("append_node", [] {
TestNode node{NodeType::Document};
expect_eq(node.child_nodes().size(), static_cast<std::size_t>(0));
 
node.append_child(std::make_shared<TestNode>(NodeType::Element));
expect_eq(node.child_nodes().size(), static_cast<std::size_t>(1));
 
node.append_child(std::make_shared<TestNode>(NodeType::Comment));
expect_eq(node.child_nodes().size(), static_cast<std::size_t>(2));
});
 
etest::test("has_child_nodes", [] {
TestNode node{NodeType::Document};
expect(!node.has_child_nodes());
node.append_child(std::make_shared<TestNode>(NodeType::Element));
expect(node.has_child_nodes());
});
 
etest::test("first_child", [] {
TestNode node{NodeType::Document};
expect_eq(node.first_child(), nullptr);
 
node.append_child(std::make_shared<TestNode>(NodeType::Element));
require(node.first_child() != nullptr);
expect_eq(node.first_child()->type(), NodeType::Element);
 
node.append_child(std::make_shared<TestNode>(NodeType::Comment));
require(node.first_child() != nullptr);
expect_eq(node.first_child()->type(), NodeType::Element);
});
 
etest::test("last_child", [] {
TestNode node{NodeType::Document};
expect_eq(node.last_child(), nullptr);
 
node.append_child(std::make_shared<TestNode>(NodeType::Element));
require(node.last_child() != nullptr);
expect_eq(node.last_child()->type(), NodeType::Element);
 
node.append_child(std::make_shared<TestNode>(NodeType::Comment));
require(node.last_child() != nullptr);
expect_eq(node.last_child()->type(), NodeType::Comment);
});
 
return etest::run_all_tests();
}
 
ev/null added: 27, removed: 947, total 0
@@ -1,29 +0,0 @@
// SPDX-FileCopyrightText: 2021 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#ifndef DOM2_PROCESSING_INSTRUCTION_H_
#define DOM2_PROCESSING_INSTRUCTION_H_
 
#include "dom2/character_data.h"
 
#include <string>
 
namespace dom2 {
 
// https://dom.spec.whatwg.org/#interface-processinginstruction
class ProcessingInstruction final : public CharacterData {
public:
ProcessingInstruction() : CharacterData(std::string{""}) {}
 
[[nodiscard]] NodeType type() const override { return NodeType::ProcessingInstruction; }
 
[[nodiscard]] std::string const &target() const { return target_; }
 
private:
std::string target_{};
};
 
} // namespace dom2
 
#endif
 
ev/null added: 27, removed: 947, total 0
@@ -1,29 +0,0 @@
// SPDX-FileCopyrightText: 2021 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#include "dom2/processing_instruction.h"
 
#include "etest/etest.h"
 
#include <string_view>
 
using namespace std::literals;
using etest::expect_eq;
 
using namespace dom2;
 
int main() {
etest::test("type", [] {
ProcessingInstruction node{};
expect_eq(node.type(), NodeType::ProcessingInstruction);
});
 
etest::test("target", [] {
ProcessingInstruction node{};
expect_eq(node.data(), ""sv);
expect_eq(node.target(), ""sv);
});
 
return etest::run_all_tests();
}
 
ev/null added: 27, removed: 947, total 0
@@ -1,17 +0,0 @@
// SPDX-FileCopyrightText: 2021 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#ifndef DOM2_SHADOW_ROOT_H_
#define DOM2_SHADOW_ROOT_H_
 
#include "dom2/document_fragment.h"
 
namespace dom2 {
 
// https://dom.spec.whatwg.org/#interface-shadowroot
class ShadowRoot final : public DocumentFragment {};
 
} // namespace dom2
 
#endif
 
ev/null added: 27, removed: 947, total 0
@@ -1,25 +0,0 @@
// SPDX-FileCopyrightText: 2021 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#ifndef DOM2_TEXT_H_
#define DOM2_TEXT_H_
 
#include "dom2/character_data.h"
 
#include <string>
#include <utility>
 
namespace dom2 {
 
// https://dom.spec.whatwg.org/#interface-text
class Text : public CharacterData {
public:
explicit Text(std::string data = std::string{""}) : CharacterData(std::move(data)) {}
 
[[nodiscard]] NodeType type() const override { return NodeType::Text; }
};
 
} // namespace dom2
 
#endif
 
ev/null added: 27, removed: 947, total 0
@@ -1,20 +0,0 @@
// SPDX-FileCopyrightText: 2021 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#include "dom2/text.h"
 
#include "etest/etest.h"
 
using etest::expect_eq;
 
using namespace dom2;
 
int main() {
etest::test("type", [] {
Text node{};
expect_eq(node.type(), NodeType::Text);
});
 
return etest::run_all_tests();
}