# selparsecss-selector

[![npm package version](https://img.shields.io/npm/v/selparsecss-selector) ![npm downloads](https://img.shields.io/npm/dm/selparsecss-selector)](https://www.npmjs.com/package/selparsecss-selector)

> A lightweight CSS selector parser providing built-in methods to parse, transform, and work with selector strings.

## Install

With [npm](https://npmjs.com/package/selparsecss-selector) do:

```
npm install selparsecss-selector
```

## Quick Start

```js
const selparser = require('selparsecss-selector');
const transform = selectors => {
    selectors.walk(selector => {
        // do something with the selector
        console.log(String(selector))
    });
};

const transformed = selparser(transform).processSync('h1, h2, h3','h4');
```

To normalize selector whitespace:

```js
const selparser = require('selparsecss-selector');
const normalized = selparser().processSync('h1, h2, h3','h4', {lossless: false});
// -> h1,h2,h3,h4
```

Async support is provided through `parser.process` and will resolve a Promise
with the resulting selector string.

## API

Please see [API.md](API.md).

## Notes

### Selector nesting depth (CVE-2026-9358)

The parser walks the selector AST recursively, both when parsing and when
serializing it back to a string (`.toString()`). In versions up to and
including `2.1.0`, a selector with extreme nesting — for example thousands of
nested `:not(...)` — could recurse deeply enough to overflow the call stack and
throw `RangeError: Maximum call stack size exceeded`, a potential
denial-of-service when processing untrusted CSS.

This is now bounded by a maximum nesting depth (default: `256`). Beyond that
depth, parsing and serialization throw a regular, catchable `Error` at a
predictable point instead of relying on the runtime hitting its stack limit.
The default is far above any realistic selector, so it does not affect normal
use.

**Practical impact is low.** The only attacker-controlled input is the selector
string itself, which is now capped by the default limit. The limit is
adjustable through the `maxNestingDepth` option, but that option is trusted
configuration provided by the integrating code — it is never derived from the
parsed CSS, so a malicious selector cannot change it:

```js
// Tighten the limit when parsing untrusted input:
selparser().processSync(untrustedSelector, {maxNestingDepth: 128});
```

Raising `maxNestingDepth` to a very large value is an explicit, informed choice
and can reintroduce the stack-overflow risk in environments with a small call
stack (e.g. browser workers). The default is recommended unless you have a
specific need.


## License

MIT
