+// 🍋🏷 Lemon ∷ window/mod.js
+// ====================================================================
+//
+// Copyright © 2022 Lady [@ Lady’s Computer].
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// 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/>.
+
+import { DOMImplementation, Node, xhtmlNamespace } from "./deps.js";
+
+{ // Polyfill document.
+ globalThis.document = new DOMImplementation().createDocument(
+ xhtmlNamespace,
+ "html",
+ null,
+ );
+ const { documentElement } = document;
+ documentElement.appendChild(
+ document.createElementNS(xhtmlNamespace, "head"),
+ );
+ documentElement.appendChild(
+ document.createElementNS(xhtmlNamespace, "body"),
+ );
+}
+
+{ // Polyfill `element.append`.
+ Object.getPrototypeOf(
+ globalThis.document.documentElement,
+ ).append = function (...children) {
+ for (const child of children) {
+ this.appendChild(
+ typeof child === "string"
+ ? this.ownerDocument.createTextNode(child)
+ : child,
+ );
+ }
+ };
+}
+
+{ // Apply patches to `Node.nodeType` and `Node.normalize`.
+ const { TEXT_NODE, prototype: nodePrototype } = Node;
+ const originalNodeTypeGetter = Object.getOwnPropertyDescriptor(
+ nodePrototype,
+ "nodeType",
+ )?.get ?? (() => {
+ const originalNodeTypeValue = nodePrototype.nodeType;
+ return () => originalNodeTypeValue;
+ })();
+ Object.defineProperty(nodePrototype, "nodeType", {
+ configurable: true,
+ enumerable: true,
+ /**
+ * To simulate restrictions on calling `nodeType` only on actual
+ * Nodes, check for inheritance first.
+ */
+ get() {
+ if (!(this instanceof Node)) {
+ // This is not a Node.
+ throw new TypeError("nodeType requires this be a Node.");
+ } else {
+ // This is a Node; walk the prototype chain and attempt to get
+ // the node type.
+ for (
+ //deno-lint-ignore no-this-alias
+ let target = this;
+ target != null && target != nodePrototype;
+ target = Object.getPrototypeOf(target)
+ ) {
+ if (Object.hasOwn(target, "nodeType")) {
+ return Reflect.get(target, "nodeType", this);
+ } else {
+ continue;
+ }
+ }
+ return originalNodeTypeGetter.call(this);
+ }
+ },
+ set: undefined,
+ });
+ nodePrototype.normalize = function () {
+ let child = this.firstChild;
+ while (child) {
+ const next = child.nextSibling;
+ if (
+ next && next.nodeType == TEXT_NODE &&
+ child.nodeType == TEXT_NODE
+ ) {
+ this.removeChild(next);
+ child.appendData(next.data);
+ } else {
+ if (child.nodeType == TEXT_NODE && !child.data) {
+ this.removeChild(child);
+ } else {
+ child.normalize();
+ }
+ child = next;
+ }
+ }
+ };
+}