UNPKG

jsdom

Version:

A JavaScript implementation of many web standards

79 lines (57 loc) 2.82 kB
"use strict"; const { HTML_NS } = require("./namespaces"); const { createElement, getValidTagNames } = require("./create-element"); const { implForWrapper, wrapperForImpl } = require("../generated/utils"); // https://html.spec.whatwg.org/multipage/custom-elements.html#concept-already-constructed-marker const ALREADY_CONSTRUCTED_MARKER = Symbol("already-constructed-marker"); // https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor function HTMLConstructor(globalObject, constructorName, newTarget) { const registry = implForWrapper(globalObject._customElementRegistry); if (newTarget === HTMLConstructor) { throw new TypeError("Invalid constructor"); } const definition = registry._customElementDefinitions.find(entry => entry.objectReference === newTarget); if (definition === undefined) { throw new TypeError("Invalid constructor, the constructor is not part of the custom element registry"); } let isValue = null; if (definition.localName === definition.name) { if (constructorName !== "HTMLElement") { throw new TypeError("Invalid constructor, autonomous custom element should extend from HTMLElement"); } } else { const validLocalNames = getValidTagNames(HTML_NS, constructorName); if (!validLocalNames.includes(definition.localName)) { throw new TypeError(`${definition.localName} is not valid local name for ${constructorName}`); } isValue = definition.name; } let { prototype } = newTarget; if (prototype === null || typeof prototype !== "object") { // The following line deviates from the specification. The HTMLElement prototype should be retrieved from the realm // associated with the "new.target". Because it is impossible to get such information in jsdom, we fallback to the // HTMLElement prototype associated with the current object. prototype = globalObject.HTMLElement.prototype; } if (definition.constructionStack.length === 0) { const documentImpl = implForWrapper(globalObject.document); const elementImpl = createElement(documentImpl, definition.localName, HTML_NS); const element = wrapperForImpl(elementImpl); Object.setPrototypeOf(element, prototype); elementImpl._ceState = "custom"; elementImpl._ceDefinition = definition; elementImpl._isValue = isValue; return element; } const elementImpl = definition.constructionStack[definition.constructionStack.length - 1]; const element = wrapperForImpl(elementImpl); if (elementImpl === ALREADY_CONSTRUCTED_MARKER) { throw new TypeError("This instance is already constructed"); } Object.setPrototypeOf(element, prototype); definition.constructionStack[definition.constructionStack.length - 1] = ALREADY_CONSTRUCTED_MARKER; return element; } module.exports = { HTMLConstructor };