aboutsummaryrefslogtreecommitdiffstats
path: root/vanilla/node_modules/@asamuzakjp/dom-selector/README.md
diff options
context:
space:
mode:
authorAdam Mathes <adam@adammathes.com>2026-02-13 21:34:48 -0800
committerAdam Mathes <adam@adammathes.com>2026-02-13 21:34:48 -0800
commit76cb9c2a39d477a64824a985ade40507e3bbade1 (patch)
tree41e997aa9c6f538d3a136af61dae9424db2005a9 /vanilla/node_modules/@asamuzakjp/dom-selector/README.md
parent819a39a21ac992b1393244a4c283bbb125208c69 (diff)
downloadneko-76cb9c2a39d477a64824a985ade40507e3bbade1.tar.gz
neko-76cb9c2a39d477a64824a985ade40507e3bbade1.tar.bz2
neko-76cb9c2a39d477a64824a985ade40507e3bbade1.zip
feat(vanilla): add testing infrastructure and tests (NK-wjnczv)
Diffstat (limited to 'vanilla/node_modules/@asamuzakjp/dom-selector/README.md')
-rw-r--r--vanilla/node_modules/@asamuzakjp/dom-selector/README.md324
1 files changed, 324 insertions, 0 deletions
diff --git a/vanilla/node_modules/@asamuzakjp/dom-selector/README.md b/vanilla/node_modules/@asamuzakjp/dom-selector/README.md
new file mode 100644
index 0000000..f4f2296
--- /dev/null
+++ b/vanilla/node_modules/@asamuzakjp/dom-selector/README.md
@@ -0,0 +1,324 @@
+# DOM Selector
+
+[![build](https://github.com/asamuzaK/domSelector/actions/workflows/node.js.yml/badge.svg)](https://github.com/asamuzaK/domSelector/actions/workflows/node.js.yml)
+[![CodeQL](https://github.com/asamuzaK/domSelector/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/asamuzaK/domSelector/actions/workflows/github-code-scanning/codeql)
+[![npm (scoped)](https://img.shields.io/npm/v/@asamuzakjp/dom-selector)](https://www.npmjs.com/package/@asamuzakjp/dom-selector)
+
+A CSS selector engine.
+
+## Install
+
+```console
+npm i @asamuzakjp/dom-selector
+```
+
+## Usage
+
+```javascript
+import { DOMSelector } from '@asamuzakjp/dom-selector';
+import { JSDOM } from 'jsdom';
+
+const { window } = new JSDOM();
+const {
+ closest, matches, querySelector, querySelectorAll
+} = new DOMSelector(window);
+```
+
+<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
+
+### matches(selector, node, opt)
+
+matches - equivalent to [Element.matches()][64]
+
+#### Parameters
+
+- `selector` **[string][59]** CSS selector
+- `node` **[object][60]** Element node
+- `opt` **[object][60]?** options
+ - `opt.noexcept` **[boolean][61]?** no exception
+ - `opt.warn` **[boolean][61]?** console warn e.g. unsupported pseudo-class
+
+Returns **[boolean][61]** `true` if matched, `false` otherwise
+
+
+### closest(selector, node, opt)
+
+closest - equivalent to [Element.closest()][65]
+
+#### Parameters
+
+- `selector` **[string][59]** CSS selector
+- `node` **[object][60]** Element node
+- `opt` **[object][60]?** options
+ - `opt.noexcept` **[boolean][61]?** no exception
+ - `opt.warn` **[boolean][61]?** console warn e.g. unsupported pseudo-class
+
+Returns **[object][60]?** matched node
+
+
+### querySelector(selector, node, opt)
+
+querySelector - equivalent to [Document.querySelector()][66], [DocumentFragment.querySelector()][67] and [Element.querySelector()][68]
+
+#### Parameters
+
+- `selector` **[string][59]** CSS selector
+- `node` **[object][60]** Document, DocumentFragment or Element node
+- `opt` **[object][60]?** options
+ - `opt.noexcept` **[boolean][61]?** no exception
+ - `opt.warn` **[boolean][61]?** console warn e.g. unsupported pseudo-class
+
+Returns **[object][60]?** matched node
+
+
+### querySelectorAll(selector, node, opt)
+
+querySelectorAll - equivalent to [Document.querySelectorAll()][69], [DocumentFragment.querySelectorAll()][70] and [Element.querySelectorAll()][71]
+**NOTE**: returns Array, not NodeList
+
+#### Parameters
+
+- `selector` **[string][59]** CSS selector
+- `node` **[object][60]** Document, DocumentFragment or Element node
+- `opt` **[object][60]?** options
+ - `opt.noexcept` **[boolean][61]?** no exception
+ - `opt.warn` **[boolean][61]?** console warn e.g. unsupported pseudo-class
+
+Returns **[Array][62]&lt;([object][60] \| [undefined][63])>** array of matched nodes
+
+
+## Monkey patch jsdom
+
+``` javascript
+import { DOMSelector } from '@asamuzakjp/dom-selector';
+import { JSDOM } from 'jsdom';
+
+const dom = new JSDOM('', {
+ runScripts: 'dangerously',
+ url: 'http://localhost/',
+ beforeParse: window => {
+ const domSelector = new DOMSelector(window);
+
+ const matches = domSelector.matches.bind(domSelector);
+ window.Element.prototype.matches = function (...args) {
+ if (!args.length) {
+ throw new window.TypeError('1 argument required, but only 0 present.');
+ }
+ const [selector] = args;
+ return matches(selector, this);
+ };
+
+ const closest = domSelector.closest.bind(domSelector);
+ window.Element.prototype.closest = function (...args) {
+ if (!args.length) {
+ throw new window.TypeError('1 argument required, but only 0 present.');
+ }
+ const [selector] = args;
+ return closest(selector, this);
+ };
+
+ const querySelector = domSelector.querySelector.bind(domSelector);
+ window.Document.prototype.querySelector = function (...args) {
+ if (!args.length) {
+ throw new window.TypeError('1 argument required, but only 0 present.');
+ }
+ const [selector] = args;
+ return querySelector(selector, this);
+ };
+ window.DocumentFragment.prototype.querySelector = function (...args) {
+ if (!args.length) {
+ throw new window.TypeError('1 argument required, but only 0 present.');
+ }
+ const [selector] = args;
+ return querySelector(selector, this);
+ };
+ window.Element.prototype.querySelector = function (...args) {
+ if (!args.length) {
+ throw new window.TypeError('1 argument required, but only 0 present.');
+ }
+ const [selector] = args;
+ return querySelector(selector, this);
+ };
+
+ const querySelectorAll = domSelector.querySelectorAll.bind(domSelector);
+ window.Document.prototype.querySelectorAll = function (...args) {
+ if (!args.length) {
+ throw new window.TypeError('1 argument required, but only 0 present.');
+ }
+ const [selector] = args;
+ return querySelectorAll(selector, this);
+ };
+ window.DocumentFragment.prototype.querySelectorAll = function (...args) {
+ if (!args.length) {
+ throw new window.TypeError('1 argument required, but only 0 present.');
+ }
+ const [selector] = args;
+ return querySelectorAll(selector, this);
+ };
+ window.Element.prototype.querySelectorAll = function (...args) {
+ if (!args.length) {
+ throw new window.TypeError('1 argument required, but only 0 present.');
+ }
+ const [selector] = args;
+ return querySelectorAll(selector, this);
+ };
+ }
+});
+```
+
+
+## Supported CSS selectors
+
+|Pattern|Supported|Note|
+|:--------|:-------:|:--------|
+|\*|✓| |
+|E|✓| |
+|ns\|E|✓| |
+|\*\|E|✓| |
+|\|E|✓| |
+|E&nbsp;F|✓| |
+|E > F|✓| |
+|E + F|✓| |
+|E ~ F|✓| |
+|F \|\| E|Unsupported| |
+|E.warning|✓| |
+|E#myid|✓| |
+|E\[foo\]|✓| |
+|E\[foo="bar"\]|✓| |
+|E\[foo="bar"&nbsp;i\]|✓| |
+|E\[foo="bar"&nbsp;s\]|✓| |
+|E\[foo~="bar"\]|✓| |
+|E\[foo^="bar"\]|✓| |
+|E\[foo$="bar"\]|✓| |
+|E\[foo*="bar"\]|✓| |
+|E\[foo\|="en"\]|✓| |
+|E:is(s1, s2, …)|✓| |
+|E:not(s1, s2, …)|✓| |
+|E:where(s1, s2, …)|✓| |
+|E:has(rs1, rs2, …)|✓| |
+|E:defined|Partially supported|Matching with MathML is not yet supported.|
+|E:dir(ltr)|✓| |
+|E:lang(en)|✓| |
+|E:any&#8209;link|✓| |
+|E:link|✓| |
+|E:visited|✓|Returns `false` or `null` to prevent fingerprinting.|
+|E:local&#8209;link|✓| |
+|E:target|✓| |
+|E:target&#8209;within|✓| |
+|E:scope|✓| |
+|E:hover|✓| |
+|E:active|✓| |
+|E:focus|✓| |
+|E:focus&#8209;visible|✓| |
+|E:focus&#8209;within|✓| |
+|E:current|Unsupported| |
+|E:current(s)|Unsupported| |
+|E:past|Unsupported| |
+|E:future|Unsupported| |
+|E:open<br>E:closed|Partially supported|Matching with &lt;select&gt;, e.g. `select:open`, is not supported.|
+|E:popover-open|✓| |
+|E:enabled<br>E:disabled|✓| |
+|E:read&#8209;write<br>E:read&#8209;only|✓| |
+|E:placeholder&#8209;shown|✓| |
+|E:default|✓| |
+|E:checked|✓| |
+|E:indeterminate|✓| |
+|E:blank|Unsupported| |
+|E:valid<br>E:invalid|✓| |
+|E:in-range<br>E:out-of-range|✓| |
+|E:required<br>E:optional|✓| |
+|E:user&#8209;valid<br>E:user&#8209;invalid|Unsupported| |
+|E:root|✓| |
+|E:empty|✓| |
+|E:nth&#8209;child(n&nbsp;[of&nbsp;S]?)|✓| |
+|E:nth&#8209;last&#8209;child(n&nbsp;[of&nbsp;S]?)|✓| |
+|E:first&#8209;child|✓| |
+|E:last&#8209;child|✓| |
+|E:only&#8209;child|✓| |
+|E:nth&#8209;of&#8209;type(n)|✓| |
+|E:nth&#8209;last&#8209;of&#8209;type(n)|✓| |
+|E:first&#8209;of&#8209;type|✓| |
+|E:last&#8209;of&#8209;type|✓| |
+|E:only&#8209;of&#8209;type|✓| |
+|E:nth&#8209;col(n)|Unsupported| |
+|E:nth&#8209;last&#8209;col(n)|Unsupported| |
+|CE:state(v)|✓|*1|
+|:host|✓| |
+|:host(s)|✓| |
+|:host(:state(v))|✓|*1|
+|:host:has(rs1, rs2, ...)|✓| |
+|:host(s):has(rs1, rs2, ...)|✓| |
+|:host&#8209;context(s)|✓| |
+|:host&#8209;context(s):has(rs1, rs2, ...)|✓| |
+|&amp;|✓|Only supports outermost `&`, i.e. equivalent to `:scope`|
+
+*1: `ElementInternals.states`, i.e. `CustomStateSet`, is not implemented in jsdom, so you need to apply a patch in the custom element constructor.
+
+``` javascript
+class LabeledCheckbox extends window.HTMLElement {
+ #internals;
+ constructor() {
+ super();
+ this.#internals = this.attachInternals();
+ // patch CustomStateSet
+ if (!this.#internals.states) {
+ this.#internals.states = new Set();
+ }
+ this.addEventListener('click', this._onClick.bind(this));
+ }
+ get checked() {
+ return this.#internals.states.has('checked');
+ }
+ set checked(flag) {
+ if (flag) {
+ this.#internals.states.add('checked');
+ } else {
+ this.#internals.states.delete('checked');
+ }
+ }
+ _onClick(event) {
+ this.checked = !this.checked;
+ }
+}
+```
+
+
+## Performance
+
+See [benchmark](https://github.com/asamuzaK/domSelector/actions/workflows/benchmark.yml) for the latest results.
+
+
+## Acknowledgments
+
+The following resources have been of great help in the development of the DOM Selector.
+
+- [CSSTree](https://github.com/csstree/csstree)
+- [selery](https://github.com/danburzo/selery)
+- [jsdom](https://github.com/jsdom/jsdom)
+- [nwsapi](https://github.com/dperini/nwsapi)
+
+---
+Copyright (c) 2023 [asamuzaK (Kazz)](https://github.com/asamuzaK/)
+
+
+[1]: #matches
+[2]: #parameters
+[3]: #closest
+[4]: #parameters-1
+[5]: #queryselector
+[6]: #parameters-2
+[7]: #queryselectorall
+[8]: #parameters-3
+[59]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
+[60]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
+[61]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
+[62]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
+[63]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/undefined
+[64]: https://developer.mozilla.org/docs/Web/API/Element/matches
+[65]: https://developer.mozilla.org/docs/Web/API/Element/closest
+[66]: https://developer.mozilla.org/docs/Web/API/Document/querySelector
+[67]: https://developer.mozilla.org/docs/Web/API/DocumentFragment/querySelector
+[68]: https://developer.mozilla.org/docs/Web/API/Element/querySelector
+[69]: https://developer.mozilla.org/docs/Web/API/Document/querySelectorAll
+[70]: https://developer.mozilla.org/docs/Web/API/DocumentFragment/querySelectorAll
+[71]: https://developer.mozilla.org/docs/Web/API/Element/querySelectorAll