Skip to content

Commit ac815ff

Browse files
committed
Revert back to nwsapi
This reverts (most of) commits c039e52 and 908f27d. Per #3659, the performance of dom-selector is currently too slow. Closes #3659.
1 parent 5b1a49e commit ac815ff

7 files changed

Lines changed: 137 additions & 115 deletions

File tree

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,47 @@
11
"use strict";
22

3-
const domSelector = require("@asamuzakjp/dom-selector");
4-
const { wrapperForImpl } = require("../generated/utils");
5-
6-
exports.matchesDontThrow = (selectors, elementImpl) => {
7-
const element = wrapperForImpl(elementImpl);
8-
try {
9-
return domSelector.matches(selectors, element);
10-
} catch {
11-
return false;
3+
const nwsapi = require("nwsapi");
4+
5+
const idlUtils = require("../generated/utils");
6+
7+
function initNwsapi(node) {
8+
const { _globalObject, _ownerDocument } = node;
9+
10+
return nwsapi({
11+
document: idlUtils.wrapperForImpl(_ownerDocument),
12+
DOMException: _globalObject.DOMException
13+
});
14+
}
15+
16+
exports.matchesDontThrow = (elImpl, selector) => {
17+
const document = elImpl._ownerDocument;
18+
19+
if (!document._nwsapiDontThrow) {
20+
document._nwsapiDontThrow = initNwsapi(elImpl);
21+
document._nwsapiDontThrow.configure({
22+
LOGERRORS: false,
23+
VERBOSITY: false,
24+
IDS_DUPES: true,
25+
MIXEDCASE: true
26+
});
1227
}
13-
};
1428

15-
exports.matches = (selectors, elementImpl) => {
16-
const element = wrapperForImpl(elementImpl);
17-
return domSelector.matches(selectors, element);
29+
return document._nwsapiDontThrow.match(selector, idlUtils.wrapperForImpl(elImpl));
1830
};
1931

20-
exports.closest = (selectors, elementImpl) => {
21-
const element = wrapperForImpl(elementImpl);
22-
return domSelector.closest(selectors, element);
23-
};
32+
// nwsapi gets `document.documentElement` at creation-time, so we have to initialize lazily, since in the initial
33+
// stages of Document initialization, there is no documentElement present yet.
34+
exports.addNwsapi = parentNode => {
35+
const document = parentNode._ownerDocument;
2436

25-
exports.querySelector = (selectors, parentNodeImpl) => {
26-
const node = wrapperForImpl(parentNodeImpl);
27-
return domSelector.querySelector(selectors, node);
28-
};
37+
if (!document._nwsapi) {
38+
document._nwsapi = initNwsapi(parentNode);
39+
document._nwsapi.configure({
40+
LOGERRORS: false,
41+
IDS_DUPES: true,
42+
MIXEDCASE: true
43+
});
44+
}
2945

30-
exports.querySelectorAll = (selectors, parentNodeImpl) => {
31-
const node = wrapperForImpl(parentNodeImpl);
32-
return domSelector.querySelectorAll(selectors, node);
46+
return document._nwsapi;
3347
};

lib/jsdom/living/helpers/style-rules.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
"use strict";
2-
32
const cssom = require("rrweb-cssom");
43
const { CSSStyleDeclaration } = require("cssstyle");
54
const defaultStyleSheet = require("../../browser/default-stylesheet");
@@ -169,8 +168,8 @@ exports.getDeclarationForElement = elementImpl => {
169168
return declaration;
170169
};
171170

172-
function matches(rule, elementImpl) {
173-
return matchesDontThrow(rule.selectorText, elementImpl);
171+
function matches(rule, element) {
172+
return matchesDontThrow(element, rule.selectorText);
174173
}
175174

176175
// Naive implementation of https://drafts.csswg.org/css-cascade-4/#cascading

lib/jsdom/living/nodes/Element-impl.js

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
"use strict";
2-
const { closest, matches } = require("../helpers/selectors");
2+
const { addNwsapi } = require("../helpers/selectors");
33
const { HTML_NS } = require("../helpers/namespaces");
44
const { mixin, memoizeQuery } = require("../../utils");
5+
const idlUtils = require("../generated/utils");
56
const NodeImpl = require("./Node-impl").implementation;
67
const ParentNodeImpl = require("./ParentNode-impl").implementation;
78
const ChildNodeImpl = require("./ChildNode-impl").implementation;
@@ -545,15 +546,8 @@ class ElementImpl extends NodeImpl {
545546
}
546547

547548
closest(selectors) {
548-
return closest(selectors, this);
549-
}
550-
551-
matches(selectors) {
552-
return matches(selectors, this);
553-
}
554-
555-
webkitMatchesSelector(selectors) {
556-
return matches(selectors, this);
549+
const matcher = addNwsapi(this);
550+
return matcher.closest(selectors, idlUtils.wrapperForImpl(this));
557551
}
558552

559553
// https://html.spec.whatwg.org/#reflecting-content-attributes-in-idl-attributes
@@ -592,6 +586,14 @@ ElementImpl.prototype.getElementsByClassName = memoizeQuery(function (classNames
592586
return listOfElementsWithClassNames(classNames, this);
593587
});
594588

589+
ElementImpl.prototype.matches = function (selectors) {
590+
const matcher = addNwsapi(this);
591+
592+
return matcher.match(selectors, idlUtils.wrapperForImpl(this));
593+
};
594+
595+
ElementImpl.prototype.webkitMatchesSelector = ElementImpl.prototype.matches;
596+
595597
module.exports = {
596598
implementation: ElementImpl
597599
};

lib/jsdom/living/nodes/ParentNode-impl.js

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
"use strict";
22

3+
const idlUtils = require("../generated/utils");
34
const NodeList = require("../generated/NodeList");
45
const HTMLCollection = require("../generated/HTMLCollection");
5-
const { querySelector, querySelectorAll } = require("../helpers/selectors");
6+
const { addNwsapi } = require("../helpers/selectors");
67
const { domSymbolTree } = require("../helpers/internal-constants");
78
const NODE_TYPE = require("../node-type");
89
const { convertNodesIntoNode } = require("../node");
@@ -61,16 +62,30 @@ class ParentNodeImpl {
6162
}
6263

6364
querySelector(selectors) {
64-
return querySelector(selectors, this);
65+
if (shouldAlwaysSelectNothing(this)) {
66+
return null;
67+
}
68+
const matcher = addNwsapi(this);
69+
return idlUtils.implForWrapper(matcher.first(selectors, idlUtils.wrapperForImpl(this)));
6570
}
6671

6772
// Warning for internal users: this returns a NodeList containing IDL wrappers instead of impls
6873
querySelectorAll(selectors) {
69-
const nodes = querySelectorAll(selectors, this);
70-
return NodeList.create(this._globalObject, [], { nodes });
74+
if (shouldAlwaysSelectNothing(this)) {
75+
return NodeList.create(this._globalObject, [], { nodes: [] });
76+
}
77+
const matcher = addNwsapi(this);
78+
const list = matcher.select(selectors, idlUtils.wrapperForImpl(this));
79+
80+
return NodeList.create(this._globalObject, [], { nodes: list.map(n => idlUtils.tryImplForWrapper(n)) });
7181
}
7282
}
7383

84+
function shouldAlwaysSelectNothing(elImpl) {
85+
// This is true during initialization.
86+
return elImpl === elImpl._ownerDocument && !elImpl.documentElement;
87+
}
88+
7489
module.exports = {
7590
implementation: ParentNodeImpl
7691
};

package-lock.json

Lines changed: 6 additions & 52 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
"license": "MIT",
2121
"repository": "jsdom/jsdom",
2222
"dependencies": {
23-
"@asamuzakjp/dom-selector": "^2.0.1",
2423
"cssstyle": "^4.0.1",
2524
"data-urls": "^5.0.0",
2625
"decimal.js": "^10.4.3",
@@ -29,6 +28,7 @@
2928
"http-proxy-agent": "^7.0.0",
3029
"https-proxy-agent": "^7.0.2",
3130
"is-potential-custom-element-name": "^1.0.1",
31+
"nwsapi": "^2.2.7",
3232
"parse5": "^7.1.2",
3333
"rrweb-cssom": "^0.6.0",
3434
"saxes": "^6.0.0",

0 commit comments

Comments
 (0)