/
html-constructor.js
81 lines (58 loc) · 2.67 KB
/
html-constructor.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/* eslint-disable global-require */
"use strict";
const { HTML_NS } = require("./namespaces");
const { CUSTOM_ELEMENT_STATE } = require("./custom-elements");
const { createElement, INTERFACE_TAG_MAPPING } = 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");
// TODO: Evaluate need to pass the constructor name
// https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor
function HTMLConstructor(globalObject, newTarget) {
const registry = implForWrapper(globalObject.customElements);
if (newTarget === HTMLConstructor) {
throw new TypeError("Invalid constructor");
}
const definition = registry._customElementDefinitions.find(entry => entry.ctor === 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 = INTERFACE_TAG_MAPPING[HTML_NS][constructorName];
if (!validLocalNames.tags.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") {
prototype = HTMLConstructor.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_ELEMENT_STATE.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) {
// TODO: Open spec bug, should be TypeError and not InvalidStateError.
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
};