Skip to content

Add a jsdom selector-engine adapter - #211

Merged
jdalton merged 1 commit into
dperini:masterfrom
jdalton:feat/jsdom-adapter
Sep 5, 2026
Merged

jdalton merged 1 commit into
dperini:masterfrom
jdalton:feat/jsdom-adapter

Conversation

@jdalton

@jdalton jdalton commented Sep 5, 2026 •

Copy link
Copy Markdown
Collaborator

Use nwsapi inside jsdom 30

Add a DOMSelector export alongside the existing CommonJS factory. It lets npm replace jsdom 30's @asamuzakjp/dom-selector dependency with nwsapi without patching jsdom or its DOM prototypes.

The adapter converts jsdom's internal nodes to public DOM nodes and routes queries, matches, and closest calls through nwsapi. It also supplies the CSS syntax trees that jsdom needs for stylesheet specificity. css-tree is an optional peer dependency, already supplied by jsdom 30; ordinary nwsapi callers do not load it.

The adapter loads css-tree only on the first stylesheet check(). DOM-only calls do not request it. A 256-entry cache reuses parsed selectors and generated branch text, never match results. DOM mutations stay visible, and clear(true) drops the syntax cache. The adapter checks all stylesheet rules without a subject prefilter. Existing selector bugs remain nwsapi's responsibility; this does not replace #178 or the other fixes.

Tests

On Node 26.5.0, all 11 integration tests pass both locally and through a fresh npm install of the packed adapter. Coverage includes DOM wrappers, static NodeLists, ordering, scoped and detached queries, fragments, XML, mutations, errors, stylesheet specificity, lazy loading, missing peers, and bounded syntax caching.

A local microbenchmark of 10,000 warm stylesheet checks fell from 28.54 ms to 3.00 ms (median of seven runs). This measures repeated syntax reuse, not end-to-end jsdom performance. jsdom can also load css-tree independently.

Run node --test test/jsdom-adapter.test.cjs for local checks. Run node test/jsdom-adapter-package.cjs for the real npm override check. The latter packs this checkout, installs jsdom 30.0.1 in a temporary consumer, overrides its selector dependency with that tarball, and runs the same suite without a module-cache substitution.

The original reentry path also remains observable through this installed adapter. Across 300 real Element.matches() calls, master reaches the depth-21 safety limit. With #178's factory, the same test creates one engine, makes 301 engine calls, reaches depth two, and never hits the limit. We can therefore move reentry coverage to jsdom 30 and remove the jsdom 26 alias from #210.

Scope

This is one commit targeting master. The engine change is only the lazy CommonJS export. The adapter, tests, package inclusion, optional peer declaration, and usage documentation are separate from selector fixes. The README shows an override to the published npm package, using the version of a future release containing the adapter. The existing npm release does not yet contain it. The package test uses a temporary tarball only to verify the adapter before publication.

@jdalton
jdalton force-pushed the feat/jsdom-adapter branch 11 times, most recently from a285d19 to 5975102 Compare September 5, 2026 23:43
@jdalton
jdalton merged commit 62d45eb into dperini:master Sep 5, 2026
@jdalton
jdalton deleted the feat/jsdom-adapter branch September 5, 2026 23:52
jdalton added a commit that referenced this pull request Sep 17, 2026
Consolidated commits:
- a959b4a Fix the forgiving fallback and EOF-terminated arguments
  Original author: John-David Dalton <[email protected]>
- 8a91824 Anchor the alternation in the :link and :placeholder-shown tests
  Original author: John-David Dalton <[email protected]>
- efa85cb Answer an id selector from the id map instead of walking
  Original author: John-David Dalton <[email protected]>
- 538f744 Merge pull request #179 from jdalton/fix/forgiving-and-eof
  Original author: Diego Perini <[email protected]>
- c545320 Establish shared legacy runtime initialization
  Original author: jdalton <[email protected]>
- 5d68c9b Merge pull request #197 from jdalton/refactor/legacy-runtime-init
  Original author: John-David Dalton <[email protected]>
- ec4bcf3 Merge pull request #181 from jdalton/fix/link-precedence
  Original author: Diego Perini <[email protected]>
- fe15bc3 Merge pull request #183 from jdalton/perf/id-lookup
  Original author: John-David Dalton <[email protected]>
- d7e01ee Add a jsdom selector-engine adapter
  Original author: jdalton <[email protected]>
- 62d45eb Merge pull request #211 from jdalton/feat/jsdom-adapter
  Original author: John-David Dalton <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant