Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 0 additions & 123 deletions .eslintrc.yml

This file was deleted.

32 changes: 24 additions & 8 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,42 @@ name: nwsapi
on:
push:
branches:
- main
- master
pull_request:
branches:
- main
- master

jobs:
build:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v7

- name: Setup pnpm
uses: pnpm/action-setup@v6

- name: Setup Node.js
uses: actions/setup-node@v2
uses: actions/setup-node@v7
with:
node-version: '14'
node-version: '24'
cache: pnpm

- name: Install dependencies
run: npm install
run: pnpm install --frozen-lockfile

- name: Lint
run: pnpm run lint

- name: Clone upstream test suites (sparse + shallow)
run: pnpm run upstream:clone

- name: Verify upstream pins
run: pnpm run upstream:verify

- name: Install Playwright browsers
run: pnpm exec playwright install --with-deps chromium

- name: Run tests
run: npm testIs the NodeJS yaml configuration needed in my "nwsapi" repository ?
run: pnpm test
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
node_modules/
package-lock.json
yarn.lock

# pristine upstream checkouts (pin of record lives in .gitmodules)
# anchored to repo root so test/upstream/ stays tracked
/upstream/

# playwright artifacts
test-results/
playwright-report/

# build output
dist/nwsapi.min.js
11 changes: 11 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# wpt-7aed663 sha256:9954c30501783f0c12ea5026a94cf988c8c5d2ac3ed51279cbfdd7476f92c393
[submodule "upstream/wpt"]
ignore = dirty
ref = 7aed6630812b20e6eec2a2e40594f8dfda036e00
path = upstream/wpt
url = https://github.com/web-platform-tests/wpt.git
branch = master
shallow = true
sparse-checkout = resources common dom/nodes css/selectors
verify = pnpm run test:upstream
# no-release-tag: web-platform-tests publishes no release tags; pinned by ref on master
74 changes: 49 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

Fast CSS Selectors API Engine

![](https://img.shields.io/npm/v/nwsapi.svg?colorB=orange&style=flat) ![](https://img.shields.io/github/tag/dperini/nwsapi.svg?style=flat) ![](https://img.shields.io/npm/dw/nwshttps://ko-fi.com/dperiniapi.svg?style=flat) ![](https://img.shields.io/github/issues/dperini/nwsapi.svg?style=flat)
![](https://img.shields.io/npm/v/nwsapi.svg?colorB=orange&style=flat) ![](https://img.shields.io/github/tag/dperini/nwsapi.svg?style=flat) ![](https://img.shields.io/npm/dw/nwsapi.svg?style=flat) ![](https://img.shields.io/github/issues/dperini/nwsapi.svg?style=flat)

NWSAPI is the development progress of [NWMATCHER](https://github.com/dperini/nwmatcher) aiming at [Selectors Level 4](https://www.w3.org/TR/selectors-4/) conformance. It has been completely reworked to be easily extended and maintained. It is a right-to-left selector parser and compiler written in pure Javascript with no external dependencies. It was initially thought as a cross browser library to improve event delegation and web page scraping in various frameworks but it has become a popular replacement of the native CSS selection and matching functionality in newer browsers and headless environments.

It uses [regular expressions](https://en.wikipedia.org/wiki/Regular_expression) to parse CSS selector strings and [metaprogramming](https://en.wikipedia.org/wiki/Metaprogramming) to transforms these selector strings into Javascript function resolvers. This process is executed only once for each selector string allowing memoization of the function resolvers and achieving unmatched performances.

## Installation

To include NWSAPI in a standard web page:https://ko-fi.com/dperini
Support & Sponsoring
To include NWSAPI in a standard web page:

```html
<script type="text/javascript" src="nwsapi.js"></script>
```
Expand All @@ -29,20 +29,19 @@ $ npm install nwsapi
```

NWSAPI currently supports browsers (as a global, `NW.Dom`) and headless environments (as a CommonJS module).
Support & Sponsoring

NWSAPI is an open-source project created and maintained with dedication. If you use this library in your apps, headless environments, or frameworks, please consider supporting its ongoing development!

GitHub Sponsors: Sponsor monthly tiers directly through GitHub.

Buy Me a Coffee: Make a one-time tip or contribution.

Your support helps cover development time, maintain full conformance with W3C Selectors specifications, and keep NWSAPI fast and dependency-https://ko-fi.com/dperinifree.
Support & Sponsoring
## Supported Selectors

Here is a list of all the CSS2/CSS3/CSS4 [Supported selectors](https://github.com/dperini/nwsapi/wiki/CSS-supported-selectors).

State pseudo-classes from [Selectors Level 4](https://www.w3.org/TR/selectors-4/):

* `:open` — matches `<details>`/`<dialog>` elements having the `open` attribute; open `<select>` drop-downs and `<input>` pickers are rendering states with no DOM reflection, so they never match here (per spec, matching is host/rendering defined).
* `:modal` and `:fullscreen` — match the document's `fullscreenElement` when the host exposes one; the `<dialog>` "is modal" flag has no DOM reflection.
* `:picture-in-picture` — matches the document's `pictureInPictureElement` when the host exposes one.
* `:current`, `:past`, `:future` — parsed as valid but match nothing: these moved to Selectors Level 5, which mandates they must not match when no timeline is defined (a static DOM has none). Only the bare forms are supported; the functional `:current(<selector-list>)` form (which no browser ships) is a parse error.
* `:closed` is intentionally **not** supported: the CSSWG removed it (only `:open` shipped; Chrome dropped `:closed` in 122), so like current browsers it is a parse error — use `:not(:open)`.


## Features and Compliance

Expand All @@ -57,15 +56,7 @@ You can read more about NWSAPI [features and compliance](https://github.com/dper

Returns a reference to the nearest ancestor element matching `selector`, starting at `context`. Returns `null` if no element is found. If `callback` is provided, it is invoked for the matched element.

#### `first( selector, context, callback )`Support & Sponsoring

NWSAPI is an open-source project created and maintained with dedication. If you use this library in your apps, headless environments, or frameworks, please consider supporting its ongoing development!

GitHub Sponsors: Sponsor monthly tiers directly through GitHub.
Support & Sponsoring
Buy Me a Coffee: Make a one-time tip or contribution.
https://ko-fi.com/dperini
Your support helps cover development time, maintain full conformance with W3C Selectors specifications, and keep NWSAPI fast and dependency-free.
#### `first( selector, context, callback )`

Returns a reference to the first element matching `selector`, starting at `context`. Returns `null` if no element matches. If `callback` is provided, it is invoked for the matched element.

Expand All @@ -86,7 +77,7 @@ Returns a reference to the first element with ID `id`, optionally filtered to de

#### `byTag( tag, from )`

Returns an array of elements having the specified tag name `tag`, optionally filtered to descendants of theSupport & Sponsoring element `from`.
Returns an array of elements having the specified tag name `tag`, optionally filtered to descendants of the element `from`.

#### `byClass( class, from )`

Expand All @@ -106,7 +97,7 @@ The following is the list of currently available configuration options, their de


### Examples on extending the basic functionalities
Support & Sponsoringhttps://ko-fi.com/dperini

#### `configure( { <configuration-flag>: [ true | false ] } )`

Disable logging errors/warnings to console, disallow duplicate ids. Example:
Expand All @@ -129,13 +120,13 @@ NW.Dom.registerCombinator( '^', 'e.parentElement' );
Registers a new symbol and its matching resolver in the attribute operators table. Example:

```js
NW.Dom.registerOperator( '!=', { p1: '^', p2: '$', p3: 'false' } );https://ko-fi.com/dperini
NW.Dom.registerOperator( '!=', { p1: '^', p2: '$', p3: 'false' } );
```

#### `registerSelector( name, rexp, func )`

Registers a new selector, the matching RE and the resolver function, in the selectors table. Example:
Support & Sponsoring

```js
NW.Dom.registerSelector('Controls', /^\:(control)(.*)/i,
(function(global) {
Expand All @@ -147,6 +138,39 @@ NW.Dom.registerSelector('Controls', /^\:(control)(.*)/i,
})(this));
```

## Development

Requires Node.js >= 24 and [pnpm](https://pnpm.io) (the version pinned in `packageManager`).

```sh
pnpm install # install pinned dev dependencies
pnpm run lint # eslint (flat config)
pnpm run min # build dist/nwsapi.min.js (terser)

# upstream web-platform-tests (sparse + shallow, pinned in .gitmodules)
pnpm run upstream:clone # materialize upstream/wpt at the pinned ref
pnpm run upstream:verify # verify ref, sparse patterns and manifest hash

# run upstream WPT selector tests against src/nwsapi.js (Playwright)
pnpm exec playwright install chromium
pnpm run test:upstream # full suite
WPT_FILTER='Attribute presence' pnpm run test:upstream # individual selectors
WPT_SECTION='Combinators' pnpm run test:upstream # a whole section

# benchmarks (mitata + jsdom), ported from the legacy test/speed suite
pnpm run bench # all preset groups
pnpm run bench -- --preset default # one group
pnpm run bench -- --selector 'div:not(.example)' # a single selector

# serve the WPT checkout + repo for interactive debugging via portless
pnpm run serve # -> https://nwsapi.localhost (proxies $PORT)
# first run on a new machine: `pnpm exec portless trust` once (sudo prompt)
# to install the local CA and start the HTTPS proxy
```

The `upstream/` directory is git-ignored on purpose: the pin of record is the
`ref` field in `.gitmodules` (see `docs/upstream.md`).

## 💖 Support & Sponsoring

**NWSAPI** powers millions of builds, web scrapers, and testing suites every single day—including key infrastructure like [jsdom](https://github.com/jsdom/jsdom).
Expand Down
Loading
Loading