Skip to content

Commit

Permalink
address PR feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
pmdartus committed Jan 21, 2020
1 parent c65ae09 commit 4800853
Show file tree
Hide file tree
Showing 11 changed files with 73 additions and 67 deletions.
6 changes: 4 additions & 2 deletions lib/jsdom/browser/Window.js
Expand Up @@ -225,6 +225,7 @@ function Window(options) {
const navigator = Navigator.create(window, [], { userAgent: this._resourceLoader._userAgent });
const performance = Performance.create(window, [], { rawPerformance });
const screen = Screen.create(window);
const customElementRegistry = CustomElementRegistry.create(window);

define(this, {
get length() {
Expand Down Expand Up @@ -318,6 +319,9 @@ function Window(options) {
}

return this._sessionStorage;
},
get customElements() {
return customElementRegistry;
}
});

Expand Down Expand Up @@ -577,8 +581,6 @@ function Window(options) {
return window._document.getSelection();
};

this.customElements = CustomElementRegistry.create(window);

// The captureEvents() and releaseEvents() methods must do nothing
this.captureEvents = function () {};

Expand Down
10 changes: 5 additions & 5 deletions lib/jsdom/browser/parser/html.js
Expand Up @@ -14,7 +14,7 @@ const nodeTypes = require("../../living/node-type");

const serializationAdapter = require("../../living/domparsing/parse5-adapter-serialization");
const {
CUSTOM_ELEMENT_REACTIONS_STACK, invokeCEReactions, lookupCEDefinition
customElementReactionsStack, invokeCEReactions, lookupCEDefinition
} = require("../../living/helpers/custom-elements");

const OpenElementStack = require("parse5/lib/parser/open-element-stack");
Expand Down Expand Up @@ -95,17 +95,17 @@ class JSDOMParse5Adapter {
}

if (willExecuteScript) {
ownerDocument._throwOwnDynamicMarkupInsertionCounter++;
CUSTOM_ELEMENT_REACTIONS_STACK.push([]);
ownerDocument._throwOnDynamicMarkupInsertionCounter++;
customElementReactionsStack.push([]);
}

const element = createElement(ownerDocument, localName, namespace, null, isValue, willExecuteScript);
this.adoptAttributes(element, attrs);

if (willExecuteScript) {
const queue = CUSTOM_ELEMENT_REACTIONS_STACK.pop();
const queue = customElementReactionsStack.pop();
invokeCEReactions(queue);
ownerDocument._throwOwnDynamicMarkupInsertionCounter--;
ownerDocument._throwOnDynamicMarkupInsertionCounter--;
}

if ("_parserInserted" in element) {
Expand Down
10 changes: 5 additions & 5 deletions lib/jsdom/living/attributes.js
Expand Up @@ -5,7 +5,7 @@ const attrGenerated = require("./generated/Attr");
const { HTML_NS } = require("./helpers/namespaces");
const { asciiLowercase } = require("./helpers/strings");
const { queueAttributeMutationRecord } = require("./helpers/mutation-observers");
const { CUSTOM_ELEMENT_STATE, enqueueCECallbackReaction } = require("./helpers/custom-elements");
const { enqueueCECallbackReaction } = require("./helpers/custom-elements");

// The following three are for https://dom.spec.whatwg.org/#concept-element-attribute-has. We don't just have a
// predicate tester since removing that kind of flexibility gives us the potential for better future optimizations.
Expand Down Expand Up @@ -33,7 +33,7 @@ exports.changeAttribute = function (element, attribute, value) {

queueAttributeMutationRecord(element, _localName, _namespace, _value);

if (element._ceState === CUSTOM_ELEMENT_STATE.CUSTOM) {
if (element._ceState === "custom") {
enqueueCECallbackReaction(element, "attributeChangedCallback", [
_localName,
_value,
Expand All @@ -55,7 +55,7 @@ exports.appendAttribute = function (element, attribute) {

queueAttributeMutationRecord(element, _localName, _namespace, null);

if (element._ceState === CUSTOM_ELEMENT_STATE.CUSTOM) {
if (element._ceState === "custom") {
enqueueCECallbackReaction(element, "attributeChangedCallback", [
_localName,
null,
Expand Down Expand Up @@ -90,7 +90,7 @@ exports.removeAttribute = function (element, attribute) {

queueAttributeMutationRecord(element, _localName, _namespace, _value);

if (element._ceState === CUSTOM_ELEMENT_STATE.CUSTOM) {
if (element._ceState === "custom") {
enqueueCECallbackReaction(element, "attributeChangedCallback", [
_localName,
_value,
Expand Down Expand Up @@ -130,7 +130,7 @@ exports.replaceAttribute = function (element, oldAttr, newAttr) {

queueAttributeMutationRecord(element, _localName, _namespace, _value);

if (element._ceState === CUSTOM_ELEMENT_STATE.CUSTOM) {
if (element._ceState === "custom") {
enqueueCECallbackReaction(element, "attributeChangedCallback", [
_localName,
_value,
Expand Down
Expand Up @@ -31,6 +31,10 @@ function convertToSequenceDOMString(obj) {
// Returns true is the passed value is a valid constructor.
// Borrowed from: https://stackoverflow.com/a/39336206/3832710
function isConstructor(value) {
if (typeof value !== "function") {
return false;
}

try {
const P = new Proxy(value, {
construct() {
Expand All @@ -42,7 +46,7 @@ function isConstructor(value) {
new P();

return true;
} catch (err) {
} catch {
return false;
}
}
Expand All @@ -61,7 +65,7 @@ class CustomElementRegistryImpl {
define(name, ctor, options) {
const { _globalObject } = this;

if (typeof ctor !== "function" || !isConstructor(ctor)) {
if (!isConstructor(ctor)) {
throw new TypeError("Constructor argument is not a constructor.");
}

Expand Down
19 changes: 17 additions & 2 deletions lib/jsdom/living/domparsing/parse5-adapter-serialization.js
@@ -1,5 +1,4 @@
"use strict";
const idlUtils = require("../generated/utils");
const nodeTypes = require("../node-type");
const { domSymbolTree } = require("../helpers/internal-constants");
// Serialization only requires a subset of the tree adapter interface.
Expand All @@ -11,7 +10,23 @@ exports.getChildNodes = node => node.childNodesForSerializing || domSymbolTree.c

exports.getParentNode = node => node.parentNode;

exports.getAttrList = node => idlUtils.wrapperForImpl(node._attributes);
exports.getAttrList = element => {
const attributeList = [...element._attributeList];

if (
element._isValue &&
attributeList.every(attr => attr.name !== "is")
) {
attributeList.unshift({
name: "is",
namespace: null,
prefix: null,
value: element._isValue
});
}

return attributeList;
};

// Node data
exports.getTagName = element => element._qualifiedName; // https://github.com/inikulin/parse5/issues/231
Expand Down
14 changes: 6 additions & 8 deletions lib/jsdom/living/helpers/create-element.js
Expand Up @@ -11,11 +11,9 @@ const { domSymbolTree } = require("./internal-constants");
const { validateAndExtract } = require("./validate-names");
const reportException = require("./runtime-script-errors");
const {
CUSTOM_ELEMENT_STATE, isValidCustomElementName, upgradeElement, lookupCEDefinition,
enqueueCEUpgradeReaction
isValidCustomElementName, upgradeElement, lookupCEDefinition, enqueueCEUpgradeReaction
} = require("./custom-elements");


const INTERFACE_TAG_MAPPING = {
// https://html.spec.whatwg.org/multipage/dom.html#elements-in-the-dom%3Aelement-interface
// https://html.spec.whatwg.org/multipage/indices.html#elements-3
Expand Down Expand Up @@ -181,7 +179,7 @@ function createElement(document, localName, namespace, prefix = null, isValue =
localName,
namespace: HTML_NS,
prefix,
ceState: CUSTOM_ELEMENT_STATE.UNDEFINED,
ceState: "undefined",
ceDefinition: null,
isValue
});
Expand Down Expand Up @@ -233,7 +231,7 @@ function createElement(document, localName, namespace, prefix = null, isValue =
localName,
namespace: HTML_NS,
prefix,
ceState: CUSTOM_ELEMENT_STATE.FAILED,
ceState: "failed",
ceDefinition: null,
isValue: null
});
Expand All @@ -245,7 +243,7 @@ function createElement(document, localName, namespace, prefix = null, isValue =
localName,
namespace: HTML_NS,
prefix,
ceState: CUSTOM_ELEMENT_STATE.UNDEFINED,
ceState: "undefined",
ceDefinition: null,
isValue: null
});
Expand Down Expand Up @@ -274,13 +272,13 @@ function createElement(document, localName, namespace, prefix = null, isValue =
localName,
namespace,
prefix,
ceState: CUSTOM_ELEMENT_STATE.UNCUSTOMIZED,
ceState: "uncustomized",
ceDefinition: null,
isValue
});

if (namespace === HTML_NS && (isValidCustomElementName(localName) || isValue !== null)) {
result._ceState = CUSTOM_ELEMENT_STATE.UNDEFINED;
result._ceState = "undefined";
}
}

Expand Down
41 changes: 16 additions & 25 deletions lib/jsdom/living/helpers/custom-elements.js
Expand Up @@ -10,14 +10,6 @@ const reportException = require("./runtime-script-errors");

const { implForWrapper, wrapperForImpl } = require("../generated/utils");

// https://dom.spec.whatwg.org/#concept-element-custom-element-state
const CUSTOM_ELEMENT_STATE = {
UNDEFINED: "undefined",
FAILED: "failed",
UNCUSTOMIZED: "uncustomized",
CUSTOM: "custom"
};

// https://html.spec.whatwg.org/multipage/custom-elements.html#custom-element-reactions-stack
class CEReactionsStack {
constructor() {
Expand Down Expand Up @@ -48,14 +40,14 @@ class CEReactionsStack {
}
}

const CUSTOM_ELEMENT_REACTIONS_STACK = new CEReactionsStack();
const customElementReactionsStack = new CEReactionsStack();

// https://html.spec.whatwg.org/multipage/custom-elements.html#cereactions
function ceReactionsPreSteps() {
CUSTOM_ELEMENT_REACTIONS_STACK.push([]);
customElementReactionsStack.push([]);
}
function ceReactionsPostSteps() {
const queue = CUSTOM_ELEMENT_REACTIONS_STACK.pop();
const queue = customElementReactionsStack.pop();
invokeCEReactions(queue);
}

Expand All @@ -81,12 +73,12 @@ function isValidCustomElementName(name) {

// https://html.spec.whatwg.org/multipage/custom-elements.html#concept-upgrade-an-element
function upgradeElement(definition, element) {
if (element._ceState !== CUSTOM_ELEMENT_STATE.UNDEFINED || element._ceState === CUSTOM_ELEMENT_STATE.UNCUSTOMIZED) {
if (element._ceState !== "undefined" || element._ceState === "uncustomized") {
return;
}

element._ceDefinition = definition;
element._ceState = CUSTOM_ELEMENT_STATE.FAILED;
element._ceState = "failed";

for (const attribute of element._attributeList) {
const { _localName, _namespace, _value } = attribute;
Expand Down Expand Up @@ -129,7 +121,7 @@ function upgradeElement(definition, element) {
throw constructionError;
}

element._ceState = CUSTOM_ELEMENT_STATE.CUSTOM;
element._ceState = "custom";
}

// https://html.spec.whatwg.org/#concept-try-upgrade
Expand All @@ -154,7 +146,7 @@ function lookupCEDefinition(document, namespace, localName, isValue) {
return definition;
}

const registry = implForWrapper(document._defaultView.customElements);
const registry = implForWrapper(document._globalObject.customElements);

const definitionByName = registry._customElementDefinitions.find(def => {
return def.name === def.localName && def.localName === localName;
Expand Down Expand Up @@ -193,30 +185,30 @@ function invokeCEReactions(elementQueue) {
}
}
} catch (error) {
reportException(element._ownerDocument._defaultView, error);
reportException(element._globalObject, error);
}
}
}

// https://html.spec.whatwg.org/multipage/custom-elements.html#enqueue-an-element-on-the-appropriate-element-queue
function enqueueElementOnAppropriateElementQueue(element) {
if (CUSTOM_ELEMENT_REACTIONS_STACK.isEmpty()) {
CUSTOM_ELEMENT_REACTIONS_STACK.backupElementQueue.push(element);
if (customElementReactionsStack.isEmpty()) {
customElementReactionsStack.backupElementQueue.push(element);

if (CUSTOM_ELEMENT_REACTIONS_STACK.processingBackupElementQueue) {
if (customElementReactionsStack.processingBackupElementQueue) {
return;
}

CUSTOM_ELEMENT_REACTIONS_STACK.processingBackupElementQueue = true;
customElementReactionsStack.processingBackupElementQueue = true;

Promise.resolve().then(() => {
const elementQueue = CUSTOM_ELEMENT_REACTIONS_STACK.backupElementQueue;
const elementQueue = customElementReactionsStack.backupElementQueue;
invokeCEReactions(elementQueue);

CUSTOM_ELEMENT_REACTIONS_STACK.processingBackupElementQueue = false;
customElementReactionsStack.processingBackupElementQueue = false;
});
} else {
CUSTOM_ELEMENT_REACTIONS_STACK.currentElementQueue.push(element);
customElementReactionsStack.currentElementQueue.push(element);
}
}

Expand Down Expand Up @@ -256,8 +248,7 @@ function enqueueCEUpgradeReaction(element, definition) {
}

module.exports = {
CUSTOM_ELEMENT_STATE,
CUSTOM_ELEMENT_REACTIONS_STACK,
customElementReactionsStack,

ceReactionsPreSteps,
ceReactionsPostSteps,
Expand Down
5 changes: 1 addition & 4 deletions lib/jsdom/living/helpers/html-constructor.js
@@ -1,9 +1,6 @@
/* eslint-disable global-require */

"use strict";

const { HTML_NS } = require("./namespaces");
const { CUSTOM_ELEMENT_STATE } = require("./custom-elements");
const { createElement, getValidTagNames } = require("./create-element");

const { implForWrapper, wrapperForImpl } = require("../generated/utils");
Expand Down Expand Up @@ -55,7 +52,7 @@ function HTMLConstructor(globalObject, constructorName, newTarget) {
const element = wrapperForImpl(elementImpl);
Object.setPrototypeOf(element, prototype);

elementImpl._ceState = CUSTOM_ELEMENT_STATE.CUSTOM;
elementImpl._ceState = "custom";
elementImpl._ceDefinition = definition;
elementImpl._isValue = isValue;

Expand Down
8 changes: 4 additions & 4 deletions lib/jsdom/living/nodes/Document-impl.js
Expand Up @@ -25,7 +25,7 @@ const validateName = require("../helpers/validate-names").name;
const { validateAndExtract } = require("../helpers/validate-names");
const { fireAnEvent } = require("../helpers/events");
const { shadowIncludingInclusiveDescendantsIterator } = require("../helpers/shadow-dom");
const { enqueueCECallbackReaction, CUSTOM_ELEMENT_STATE } = require("../helpers/custom-elements");
const { enqueueCECallbackReaction } = require("../helpers/custom-elements");
const { createElement, createElementNS } = require("../helpers/create-element");

const DocumentOrShadowRootImpl = require("./DocumentOrShadowRoot-impl").implementation;
Expand Down Expand Up @@ -197,7 +197,7 @@ class DocumentImpl extends NodeImpl {
this._latestEntry = null;

// https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#throw-on-dynamic-markup-insertion-counter
this._throwOwnDynamicMarkupInsertionCounter = 0;
this._throwOnDynamicMarkupInsertionCounter = 0;
}

_getTheParent(event) {
Expand Down Expand Up @@ -301,7 +301,7 @@ class DocumentImpl extends NodeImpl {
]);
}

if (this._throwOwnDynamicMarkupInsertionCounter > 0) {
if (this._throwOnDynamicMarkupInsertionCounter > 0) {
throw DOMException.create(this._globalObject, [
"Cannot use document.write while an element upgrades",
"InvalidStateError"
Expand Down Expand Up @@ -816,7 +816,7 @@ class DocumentImpl extends NodeImpl {
}

for (const inclusiveDescendant of shadowIncludingInclusiveDescendantsIterator(node)) {
if (inclusiveDescendant._ceState === CUSTOM_ELEMENT_STATE.CUSTOM) {
if (inclusiveDescendant._ceState === "custom") {
enqueueCECallbackReaction(inclusiveDescendant, "adoptedCallback", [
idlUtils.wrapperForImpl(oldDocument),
idlUtils.wrapperForImpl(newDocument)
Expand Down

0 comments on commit 4800853

Please sign in to comment.