Skip to content

Repository files navigation

Socket Badge Coverage

NWSAPI finds DOM elements that match CSS selectors. It works in browsers and with DOM libraries in Node.js. The core engine has no external dependencies.

NWSAPI builds on NWMATCHER and aims to support Selectors Level 4. See the supported selectors and features.

Install

pnpm add nwsapi

Use the jsdom adapter

Use nwsapi ≥ 2.3.0 with jsdom ≥ 27. The adapter replaces jsdom's selector engine for queries and stylesheet matching.

Set up the dependency and override

Add the adapter's css-tree peer dependency to package.json:

{
  "dependencies": {
    "css-tree": "^3.2.1"
  }
}

Replace <version> with the published nwsapi version you want to use.

  • npm (package.json):

    {
      "overrides": {
        "@asamuzakjp/dom-selector": "npm:nwsapi@<version>"
      }
    }
  • pnpm (pnpm-workspace.yaml):

    overrides:
      '@asamuzakjp/dom-selector': 'npm:nwsapi@<version>'

Install dependencies after the change. The override does not change the NWSAPI factory API or add selector support.

Use the factory in Node.js

Node.js does not provide a DOM. This example creates one with jsdom.

pnpm add nwsapi jsdom
const { JSDOM } = require('jsdom')
const createNwsapi = require('nwsapi')
const { window } = new JSDOM('<p class="item">Hello</p>')
const nw = createNwsapi(window)

const items = nw.select('.item', window.document)
window.close()

This example calls NWSAPI directly. It does not replace jsdom's selector engine.

Use in a browser

Copy src/nwsapi.js from the package into your project. Set the script path to that file.

<script src="nwsapi.js"></script>
<script>
  const items = NW.Dom.select('.item', document)
  const firstItem = NW.Dom.first('.item', document)
</script>
Replace native selector methods

install() changes selector methods such as querySelectorAll() and matches() for the page. Use it only when you want those methods to call NWSAPI.

NW.Dom.install()
// Restore the original methods when they are no longer needed.
NW.Dom.uninstall()

API

Use NW.Dom in a browser or the engine returned by the Node.js factory. Pass a CSS selector as selector and a DOM node as context.

Method Result
ancestor(selector, element) Returns the nearest match, starting with the element, or null.
first(selector, context) Returns the first matching descendant, or null.
match(selector, element) Returns true if the element matches, or false.
select(selector, context) Returns an array of matching descendants, or [] if none match.

These methods accept an optional third argument, callback, which runs for matching elements.

Find elements by ID, tag, or class

Pass the search context as the second argument. These helpers return arrays by default.

NW.Dom.byClass('item', document)
NW.Dom.byId('content', document)
NW.Dom.byTag('p', document)

byId() can return multiple elements when the document contains duplicate IDs.

Configure the engine
NW.Dom.configure({ LOGERRORS: false, IDS_DUPES: false })
const options = NW.Dom.configure()
Option Default Effect
FORGIVING true Allows invalid items in forgiving selector lists such as :is() and :where().
IDS_DUPES true Allows duplicate IDs when finding elements.
LEGACY false Enables feature checks and fallbacks for older environments.
LOGERRORS true Logs errors when exception throwing is disabled.
NODE_LIST false Uses NodeList-style results instead of arrays where supported.
VERBOSITY true Throws exceptions for invalid selectors.

[!IMPORTANT] Set LEGACY before the first query when the environment needs compatibility fallbacks.

Add selector extensions

Extensions use JavaScript source strings to define matching behavior. Register only trusted code.

registerCombinator(symbol, resolver) adds a relationship between elements:

NW.Dom.registerCombinator('^', 'e.parentElement')

registerOperator(symbol, resolver) adds an attribute operator:

NW.Dom.registerOperator('!=', { p1: '^', p2: '$', p3: 'false' })

registerSelector(name, pattern, compile) adds a selector. The compile function returns matching code and a success flag.

NW.Dom.registerSelector('Controls', /^:(control)(.*)/i, (match, source) => ({
  source: 'if(/^(button|input|select|textarea)$/i.test(e.nodeName)){' + source + '}',
  status: true,
}))

The engine compiles selectors into JavaScript functions and caches those functions for later queries.

Contribute

See the contributor requirements in package.json.

pnpm install
pnpm test

The install sets up WPT and Chromium for browser tests. It needs Git and network access. Node tests do not use the browser or WPT checkout.

Check changes before a push
pnpm run check
pnpm run test:package

Run pnpm run fix to apply lint fixes, format files, and check the result. Run pnpm run test:watch to repeat Node tests while you edit files.

Run pnpm run ci:local to test the GitHub Actions workflow locally. It needs Docker and GitHub CLI authentication. It pauses when a step fails. CI uses one Node.js 26 job.

Run browser tests and measure coverage

See upstream testing for system requirements and setup recovery. WPT means Web Platform Tests.

pnpm run test:browser
pnpm run test:upstream
pnpm run test:coverage

Coverage uses WPT in Chromium for the engine and Node tests for the adapter. The coverage command checks the minimums in .config/coverage.config.mts and updates the badge. CI also creates HTML reports. Known WPT failures remain visible in test results.

Build the package and update dependencies

Rolldown builds JavaScript from the .mts source files and creates the minified browser file. Run pnpm run build to build the files. Run pnpm run clean to remove generated JavaScript.

pnpm pack and pnpm publish build the package first. Published files keep their existing paths, CommonJS API, browser and AMD support, and extension modules. The package does not include TypeScript source files or development tools.

Pin development dependencies in the pnpm-workspace.yaml catalog. Update pnpm-lock.yaml when dependencies change. Run pnpm run update --check to preview dependency updates. Run pnpm run update to apply updates and refresh the lockfile. Compiler tool versions need a separate compatibility review. New dependency versions have a one-day release delay. Dependency scripts need explicit approval. Use pnpm to install this repository; npm cannot install its catalog references. CI reads Node.js and package manager versions from .config/external-tools.json.

Support the project

Sponsorship helps fund maintenance, testing, and selector support.

Sponsorship and donation options

Use GitHub Sponsors, Open Collective, or Patreon for ongoing support.

You can also use Ko-fi, Buy Me a Coffee, or Liberapay. Use IssueHunt to fund issues.

Corporate sponsors can ask about custom licensing, dedicated support, or priority fixes.

About

Fast CSS Selectors API Engine

Resources

Stars

139 stars

Watchers

2 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

Sponsor
SponsoredKunjungi sekarang
Promo