UNPKG

12.3 kBMarkdownView Raw
1# css-select [![NPM version](http://img.shields.io/npm/v/css-select.svg)](https://npmjs.org/package/css-select) [![Build Status](https://travis-ci.com/fb55/css-select.svg?branch=master)](http://travis-ci.com/fb55/css-select) [![Downloads](https://img.shields.io/npm/dm/css-select.svg)](https://npmjs.org/package/css-select) [![Coverage](https://coveralls.io/repos/fb55/css-select/badge.svg?branch=master)](https://coveralls.io/r/fb55/css-select)
2
3A CSS selector compiler and engine
4
5## What?
6
7As a **compiler**, css-select turns CSS selectors into functions that tests if
8elements match them.
9
10As an **engine**, css-select looks through a DOM tree, searching for elements.
11Elements are tested "from the top", similar to how browsers execute CSS
12selectors.
13
14In its default configuration, css-select queries the DOM structure of the
15[`domhandler`](https://github.com/fb55/domhandler) module (also known as
16htmlparser2 DOM). To query alternative DOM structures, see [`Options`](#options)
17below.
18
19**Features:**
20
21- ๐Ÿ”ฌ Full implementation of CSS3 selectors, as well as most CSS4 selectors
22- ๐Ÿงช Partial implementation of jQuery/Sizzle extensions (see
23 [cheerio-select](https://github.com/cheeriojs/cheerio-select) for the
24 remaining selectors)
25- ๐Ÿง‘โ€๐Ÿ”ฌ High test coverage, including the full test suites from
26 [`Sizzle`](https://github.com/jquery/sizzle),
27 [`Qwery`](https://github.com/ded/qwery) and
28 [`NWMatcher`](https://github.com/dperini/nwmatcher/) and .
29- ๐Ÿฅผ Reliably great performance
30
31## Why?
32
33Most CSS engines written in JavaScript execute selectors left-to-right. That
34means thet execute every component of the selector in order, from left to right.
35As an example: For the selector `a b`, these engines will first query for `a`
36elements, then search these for `b` elements. (That's the approach of eg.
37[`Sizzle`](https://github.com/jquery/sizzle),
38[`Qwery`](https://github.com/ded/qwery) and
39[`NWMatcher`](https://github.com/dperini/nwmatcher/).)
40
41While this works, it has some downsides: Children of `a`s will be checked
42multiple times; first, to check if they are also `a`s, then, for every superior
43`a` once, if they are `b`s. Using
44[Big O notation](http://en.wikipedia.org/wiki/Big_O_notation), that would be
45`O(n^(k+1))`, where `k` is the number of descendant selectors (that's the space
46in the example above).
47
48The far more efficient approach is to first look for `b` elements, then check if
49they have superior `a` elements: Using big O notation again, that would be
50`O(n)`. That's called right-to-left execution.
51
52And that's what css-select does โ€“ and why it's quite performant.
53
54## How does it work?
55
56By building a stack of functions.
57
58_Wait, what?_
59
60Okay, so let's suppose we want to compile the selector `a b`, for right-to-left
61execution. We start by _parsing_ the selector. This turns the selector into an
62array of the building blocks. That's what the
63[`css-what`](https://github.com/fb55/css-what) module is for, if you want to
64have a look.
65
66Anyway, after parsing, we end up with an array like this one:
67
68```js
69[
70 { type: "tag", name: "a" },
71 { type: "descendant" },
72 { type: "tag", name: "b" },
73];
74```
75
76(Actually, this array is wrapped in another array, but that's another story,
77involving commas in selectors.)
78
79Now that we know the meaning of every part of the selector, we can compile it.
80That is where things become interesting.
81
82The basic idea is to turn every part of the selector into a function, which
83takes an element as its only argument. The function checks whether a passed
84element matches its part of the selector: If it does, the element is passed to
85the next function representing the next part of the selector. That function does
86the same. If an element is accepted by all parts of the selector, it _matches_
87the selector and double rainbow ALL THE WAY.
88
89As said before, we want to do right-to-left execution with all the big O
90improvements. That means elements are passed from the rightmost part of the
91selector (`b` in our example) to the leftmost (~~which would be `c`~~ of course
92`a`).
93
94For traversals, such as the _descendant_ operating the space between `a` and
95`b`, we walk up the DOM tree, starting from the element passed as argument.
96
97_//TODO: More in-depth description. Implementation details. Build a spaceship._
98
99## API
100
101```js
102const CSSselect = require("css-select");
103```
104
105**Note:** css-select throws errors when invalid selectors are passed to it. This
106is done to aid with writing css selectors, but can be unexpected when processing
107arbitrary strings.
108
109#### `CSSselect.selectAll(query, elems, options)`
110
111Queries `elems`, returns an array containing all matches.
112
113- `query` can be either a CSS selector or a function.
114- `elems` can be either an array of elements, or a single element. If it is an
115 element, its children will be queried.
116- `options` is described below.
117
118Aliases: `default` export, `CSSselect.iterate(query, elems)`.
119
120#### `CSSselect.compile(query, options)`
121
122Compiles the query, returns a function.
123
124#### `CSSselect.is(elem, query, options)`
125
126Tests whether or not an element is matched by `query`. `query` can be either a
127CSS selector or a function.
128
129#### `CSSselect.selectOne(query, elems, options)`
130
131Arguments are the same as for `CSSselect.selectAll(query, elems)`. Only returns
132the first match, or `null` if there was no match.
133
134### Options
135
136All options are optional.
137
138- `xmlMode`: When enabled, tag names will be case-sensitive. Default: `false`.
139- `rootFunc`: The last function in the stack, will be called with the last
140 element that's looked at.
141- `adapter`: The adapter to use when interacting with the backing DOM
142 structure. By default it uses the `domutils` module.
143- `context`: The context of the current query. Used to limit the scope of
144 searches. Can be matched directly using the `:scope` pseudo-class.
145- `relativeSelector`: By default, selectors are relative to the `context`,
146 which means that no parent elements of the context will be matched. (Eg.
147 `a b c` with context `b` will never give any results.) If `relativeSelector`
148 is set to `false`, selectors won't be
149 [absolutized](http://www.w3.org/TR/selectors4/#absolutizing) and selectors
150 can test for parent elements outside of the `context`.
151- `cacheResults`: Allow css-select to cache results for some selectors,
152 sometimes greatly improving querying performance. Disable this if your
153 document can change in between queries with the same compiled selector.
154 Default: `true`.
155- `pseudos`: A map of pseudo-class names to functions or strings.
156
157#### Custom Adapters
158
159A custom adapter must match the interface described
160[here](https://github.com/fb55/css-select/blob/1aa44bdd64aaf2ebdfd7f338e2e76bed36521957/src/types.ts#L6-L96).
161
162You may want to have a look at [`domutils`](https://github.com/fb55/domutils) to
163see the default implementation, or at
164[`css-select-browser-adapter`](https://github.com/nrkn/css-select-browser-adapter/blob/master/index.js)
165for an implementation backed by the DOM.
166
167## Supported selectors
168
169_As defined by CSS 4 and / or jQuery._
170
171- [Selector lists](https://developer.mozilla.org/en-US/docs/Web/CSS/Selector_list)
172 (`,`)
173- [Universal](https://developer.mozilla.org/en-US/docs/Web/CSS/Universal_selectors)
174 (`*`)
175- [Type](https://developer.mozilla.org/en-US/docs/Web/CSS/Type_selectors)
176 (`<tagname>`)
177- [Descendant](https://developer.mozilla.org/en-US/docs/Web/CSS/Descendant_combinator)
178 (` `)
179- [Child](https://developer.mozilla.org/en-US/docs/Web/CSS/Child_combinator)
180 (`>`)
181- Parent (`<`)
182- [Adjacent sibling](https://developer.mozilla.org/en-US/docs/Web/CSS/Adjacent_sibling_combinator)
183 (`+`)
184- [General sibling](https://developer.mozilla.org/en-US/docs/Web/CSS/General_sibling_combinator)
185 (`~`)
186- [Attribute](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors)
187 (`[attr=foo]`), with supported comparisons:
188 - `[attr]` (existential)
189 - `=`
190 - `~=`
191 - `|=`
192 - `*=`
193 - `^=`
194 - `$=`
195 - `!=`
196 - `i` and `s` can be added after the comparison to make the comparison
197 case-insensitive or case-sensitive (eg. `[attr=foo i]`). If neither is
198 supplied, css-select will follow the HTML spec's
199 [case-sensitivity rules](https://html.spec.whatwg.org/multipage/semantics-other.html#case-sensitivity-of-selectors).
200- Pseudos:
201 - [`:not`](https://developer.mozilla.org/en-US/docs/Web/CSS/:not)
202 - [`:contains`](https://api.jquery.com/contains-selector)
203 - `:icontains` (case-insensitive version of `:contains`)
204 - [`:has`](https://developer.mozilla.org/en-US/docs/Web/CSS/:has)
205 - [`:root`](https://developer.mozilla.org/en-US/docs/Web/CSS/:root)
206 - [`:empty`](https://developer.mozilla.org/en-US/docs/Web/CSS/:empty)
207 - [`:parent`](https://api.jquery.com/parent-selector)
208 - [`:first-child`](https://developer.mozilla.org/en-US/docs/Web/CSS/:first-child),
209 [`:last-child`](https://developer.mozilla.org/en-US/docs/Web/CSS/:last-child),
210 [`:first-of-type`](https://developer.mozilla.org/en-US/docs/Web/CSS/:first-of-type),
211 [`:last-of-type`](https://developer.mozilla.org/en-US/docs/Web/CSS/:last-of-type)
212 - [`:only-of-type`](https://developer.mozilla.org/en-US/docs/Web/CSS/:only-of-type),
213 [`:only-child`](https://developer.mozilla.org/en-US/docs/Web/CSS/:only-child)
214 - [`:nth-child`](https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-child),
215 [`:nth-last-child`](https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-last-child),
216 [`:nth-of-type`](https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-of-type),
217 [`:nth-last-of-type`](https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-last-of-type),
218 - [`:link`](https://developer.mozilla.org/en-US/docs/Web/CSS/:link),
219 [`:any-link`](https://developer.mozilla.org/en-US/docs/Web/CSS/:any-link)
220 - [`:visited`](https://developer.mozilla.org/en-US/docs/Web/CSS/:visited),
221 [`:hover`](https://developer.mozilla.org/en-US/docs/Web/CSS/:hover),
222 [`:active`](https://developer.mozilla.org/en-US/docs/Web/CSS/:active)
223 (these depend on optional `Adapter` methods, so these will only match
224 elements if implemented in `Adapter`)
225 - [`:selected`](https://api.jquery.com/selected-selector),
226 [`:checked`](https://developer.mozilla.org/en-US/docs/Web/CSS/:checked)
227 - [`:enabled`](https://developer.mozilla.org/en-US/docs/Web/CSS/:enabled),
228 [`:disabled`](https://developer.mozilla.org/en-US/docs/Web/CSS/:disabled)
229 - [`:required`](https://developer.mozilla.org/en-US/docs/Web/CSS/:required),
230 [`:optional`](https://developer.mozilla.org/en-US/docs/Web/CSS/:optional)
231 - [`:header`](https://api.jquery.com/header-selector),
232 [`:button`](https://api.jquery.com/button-selector),
233 [`:input`](https://api.jquery.com/input-selector),
234 [`:text`](https://api.jquery.com/text-selector),
235 [`:checkbox`](https://api.jquery.com/checkbox-selector),
236 [`:file`](https://api.jquery.com/file-selector),
237 [`:password`](https://api.jquery.com/password-selector),
238 [`:reset`](https://api.jquery.com/reset-selector),
239 [`:radio`](https://api.jquery.com/radio-selector) etc.
240 - [`:is`](https://developer.mozilla.org/en-US/docs/Web/CSS/:is), plus its
241 legacy alias `:matches`
242 - [`:scope`](https://developer.mozilla.org/en-US/docs/Web/CSS/:scope)
243 (uses the context from the passed options)
244
245---
246
247License: BSD-2-Clause
248
249## Security contact information
250
251To report a security vulnerability, please use the
252[Tidelift security contact](https://tidelift.com/security). Tidelift will
253coordinate the fix and disclosure.
254
255## `css-select` for enterprise
256
257Available as part of the Tidelift Subscription
258
259The maintainers of `css-select` and thousands of other packages are working with
260Tidelift to deliver commercial support and maintenance for the open source
261dependencies you use to build your applications. Save time, reduce risk, and
262improve code health, while paying the maintainers of the exact dependencies you
263use.
264[Learn more.](https://tidelift.com/subscription/pkg/npm-css-select?utm_source=npm-css-select&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)