6.5.0 • Published 9 months ago

@asamuzakjp/dom-selector v6.5.0

Weekly downloads
-
License
MIT
Repository
github
Last release
9 months ago

DOM Selector

build CodeQL npm (scoped)

A CSS selector engine.

Install

npm i @asamuzakjp/dom-selector

Usage

import { DOMSelector } from '@asamuzakjp/dom-selector';
import { JSDOM } from 'jsdom';

const { window } = new JSDOM();
const {
  closest, matches, querySelector, querySelectorAll
} = new DOMSelector(window);

matches(selector, node, opt)

matches - equivalent to Element.matches()

Parameters

  • selector string CSS selector
  • node object Element node
  • opt object? options
    • opt.noexcept boolean? no exception
    • opt.warn boolean? console warn e.g. unsupported pseudo-class

Returns boolean true if matched, false otherwise

closest(selector, node, opt)

closest - equivalent to Element.closest()

Parameters

  • selector string CSS selector
  • node object Element node
  • opt object? options
    • opt.noexcept boolean? no exception
    • opt.warn boolean? console warn e.g. unsupported pseudo-class

Returns object? matched node

querySelector(selector, node, opt)

querySelector - equivalent to Document.querySelector(), DocumentFragment.querySelector() and Element.querySelector()

Parameters

  • selector string CSS selector
  • node object Document, DocumentFragment or Element node
  • opt object? options
    • opt.noexcept boolean? no exception
    • opt.warn boolean? console warn e.g. unsupported pseudo-class

Returns object? matched node

querySelectorAll(selector, node, opt)

querySelectorAll - equivalent to Document.querySelectorAll(), DocumentFragment.querySelectorAll() and Element.querySelectorAll()
NOTE: returns Array, not NodeList

Parameters

  • selector string CSS selector
  • node object Document, DocumentFragment or Element node
  • opt object? options
    • opt.noexcept boolean? no exception
    • opt.warn boolean? console warn e.g. unsupported pseudo-class

Returns Array<(object | undefined)> array of matched nodes

Monkey patch jsdom

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

PatternSupportedNote
*
ns|E
*|E
|E
E
E:not(s1, s2, …)
E:is(s1, s2, …)
E:where(s1, s2, …)
E:has(rs1, rs2, …)
E.warning
E#myid
E[foo]
E[foo="bar"]
E[foo="bar" i]
E[foo="bar" s]
E[foo~="bar"]
E[foo^="bar"]
E[foo$="bar"]
E[foo*="bar"]
E[foo|="en"]
E:definedPartially supportedMatching with MathML is not yet supported.
E:dir(ltr)
E:lang(en)
E:anylink
E:link
E:visitedReturns false or null to prevent fingerprinting.
E:locallink
E:target
E:targetwithin
E:scope
E:currentUnsupported
E:current(s)Unsupported
E:pastUnsupported
E:futureUnsupported
E:active
E:hover
E:focus
E:focuswithin
E:focusvisible
E:openE:closedPartially supportedMatching with <select>, e.g. select:open, is not supported.
E:enabledE:disabled
E:readwriteE:readonly
E:placeholdershown
E:default
E:checked
E:indeterminate
E:validE:invalid
E:requiredE:optional
E:blankUnsupported
E:uservalidE:userinvalidUnsupported
E:root
E:empty
E:nthchild(n of S?)
E:nthlastchild(n of S?)
E:firstchild
E:lastchild
E:onlychild
E:nthoftype(n)
E:nthlastoftype(n)
E:firstoftype
E:lastoftype
E:onlyoftype
E F
E > F
E + F
E ~ F
F || EUnsupported
E:nthcol(n)Unsupported
E:nthlastcol(n)Unsupported
E:popover-open
E:state(v)*1
:host
:host(s)
:hostcontext(s)
:host(:state(v))*1
:host:has(rs1, rs2, ...)
:host(s):has(rs1, rs2, ...)
:hostcontext(s):has(rs1, rs2, ...)
&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.

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 for the latest results.

Acknowledgments

The following resources have been of great help in the development of the DOM Selector.


Copyright (c) 2023 asamuzaK (Kazz)

6.5.0

9 months ago

6.5.0-a.2

10 months ago

6.5.0-a.1

10 months ago

6.5.0-a.9

10 months ago

6.5.0-a.8

10 months ago

6.5.0-a.7

10 months ago

6.5.0-a.6

10 months ago

6.5.0-a.5

10 months ago

6.5.0-a.4

10 months ago

6.5.0-a.3

10 months ago

6.5.0-a.16

9 months ago

6.5.0-a.11

10 months ago

6.5.0-a.10

10 months ago

6.5.0-a.13

10 months ago

6.5.0-a.12

10 months ago

6.5.0-a.15

9 months ago

6.5.0-a.14

10 months ago

6.2.1

1 year ago

6.2.2

1 year ago

6.3.4

1 year ago

6.3.3

1 year ago

6.3.5

1 year ago

6.3.7

1 year ago

6.3.0

1 year ago

6.3.2

1 year ago

6.3.1

1 year ago

6.4.3

10 months ago

6.4.2

12 months ago

6.4.5

10 months ago

6.4.4

10 months ago

6.4.7

10 months ago

6.4.6

10 months ago

6.4.0

1 year ago

6.2.0

1 year ago

5.3.3

1 year ago

5.3.2

1 year ago

5.3.1

1 year ago

5.3.0

1 year ago

6.1.0

1 year ago

6.1.1

1 year ago

5.4.0

1 year ago

6.0.1

1 year ago

6.0.0

1 year ago

6.0.3

1 year ago

6.0.2

1 year ago

6.0.5

1 year ago

6.0.4

1 year ago

5.3.4

1 year ago

4.4.10

2 years ago

4.4.1

2 years ago

4.4.0

2 years ago

4.4.3

2 years ago

4.4.2

2 years ago

4.4.13

2 years ago

4.4.12

2 years ago

4.4.11

2 years ago

5.0.9

1 year ago

5.0.8

1 year ago

5.0.7

1 year ago

5.0.5

1 year ago

5.0.4

1 year ago

5.0.3

1 year ago

5.0.2

1 year ago

5.0.1

1 year ago

5.0.0

1 year ago

4.4.9

2 years ago

4.4.8

2 years ago

4.4.5

2 years ago

4.4.4

2 years ago

4.4.7

2 years ago

4.4.6

2 years ago

4.5.0-b.7

2 years ago

4.5.0-b.6

2 years ago

4.5.0-b.5

2 years ago

4.5.0-b.4

2 years ago

4.5.0-b.3

2 years ago

4.5.0-b.2

2 years ago

4.5.0-b.1

2 years ago

5.1.0

1 year ago

4.6.1

2 years ago

4.6.0

2 years ago

5.2.2

1 year ago

5.2.1

1 year ago

5.2.0

1 year ago

4.6.3

2 years ago

4.6.5

2 years ago

4.6.4

2 years ago

4.6.0-b.1

2 years ago

4.5.0

2 years ago

4.3.0

2 years ago

4.2.2

2 years ago

4.2.1

2 years ago

4.2.0

2 years ago

4.1.7

2 years ago

4.1.4

2 years ago

4.1.6

2 years ago

4.1.5

2 years ago

4.1.3

2 years ago

4.1.2

2 years ago

4.1.1

2 years ago

4.1.0

2 years ago

4.0.1

2 years ago

4.0.0

2 years ago

3.0.5

2 years ago

3.0.4

2 years ago

3.0.3

2 years ago

3.0.2

2 years ago

2.1.0-b.3

2 years ago

2.1.0-b.2

2 years ago

2.1.0-b.4

2 years ago

3.0.1

2 years ago

2.1.0-b.1

2 years ago

2.0.3-a.6

2 years ago

2.0.3-a.5

2 years ago

2.0.3-a.8

2 years ago

2.0.3-a.7

2 years ago

2.0.3-a.4

2 years ago

2.0.3-a.2

2 years ago

2.0.3-a.3

2 years ago

2.0.2

2 years ago

2.0.2-a.3

2 years ago

2.0.3-a.1

2 years ago

2.0.2-a.1

2 years ago

2.0.2-a.2

2 years ago

2.0.1

2 years ago

2.0.0

2 years ago

1.2.8

2 years ago

1.2.7

2 years ago

1.2.6

2 years ago

1.2.5

2 years ago

1.2.4

2 years ago

1.2.3

2 years ago

1.2.2

2 years ago

1.2.1

2 years ago

1.2.0

2 years ago

1.1.14

2 years ago

1.1.13

2 years ago

1.1.9

2 years ago

1.1.8

2 years ago

1.1.6

2 years ago

1.1.5

2 years ago

1.1.4

2 years ago

1.1.3

2 years ago

1.1.12

2 years ago

1.1.11

2 years ago

1.1.10

2 years ago

1.0.2

2 years ago

1.0.1

2 years ago

1.0.0

2 years ago

1.0.5

2 years ago

1.0.4

2 years ago

1.0.3

2 years ago

1.1.1

2 years ago

1.1.0

2 years ago

1.1.2

2 years ago

0.24.0

2 years ago

0.23.2

2 years ago

0.21.2

2 years ago

0.21.1

2 years ago

0.21.0

2 years ago

0.22.0

2 years ago

0.20.1

2 years ago

0.20.0

2 years ago

0.19.4

3 years ago

0.19.5

2 years ago

0.19.6

2 years ago

0.20.2

2 years ago

0.15.4

3 years ago

0.19.1

3 years ago

0.15.5

3 years ago

0.19.2

3 years ago

0.15.6

3 years ago

0.19.3

3 years ago

0.15.7

3 years ago

0.15.8

3 years ago

0.15.9

3 years ago

0.17.0

3 years ago

0.15.3

3 years ago

0.18.1

3 years ago

0.16.3

3 years ago

0.16.4

3 years ago

0.16.0

3 years ago

0.16.1

3 years ago

0.18.0

3 years ago

0.16.2

3 years ago

0.15.10

3 years ago

0.15.13

3 years ago

0.15.12

3 years ago

0.15.1

3 years ago

0.14.0

3 years ago

0.13.5

3 years ago

0.13.2

3 years ago

0.13.1

3 years ago

0.12.8

3 years ago

0.12.7

3 years ago

0.12.6

3 years ago

0.12.5

3 years ago

0.12.3

3 years ago

0.12.2

3 years ago

0.12.1

3 years ago

0.12.0

3 years ago

0.11.1

3 years ago

0.10.0

3 years ago

0.9.2

3 years ago

0.8.1

3 years ago

0.8.0

3 years ago

0.7.0

3 years ago

0.6.2

3 years ago

0.6.1

3 years ago

0.6.0

3 years ago

0.5.0

3 years ago

0.4.2

3 years ago

0.4.1

3 years ago

0.3.0

3 years ago

0.2.2

3 years ago

0.2.1

3 years ago