Wrapper Architecture Overview
Relevant source files
The following files were used as context for generating this wiki page:
cheerio-select acts as a specialized wrapper around the css-select library, designed to extend standard CSS selector capabilities with jQuery-style positional pseudo-selectors. Its primary purpose is to provide a compatible selection engine for projects that require complex filtering logic not natively supported by standard CSS specifications, such as index-based selection (:eq, :lt, :gt) and parity-based selection (:even, :odd).
The architecture follows a hybrid approach: it delegates standard CSS selectors to css-select while intercepting and manually processing "positional" selectors. This allows the engine to maintain high performance for standard queries while enabling advanced traversal and filtering techniques required for Cheerio and similar DOM manipulation libraries.
Sources: README.md:1-12, src/index.ts:1-20, package.json:3-5
Core Selection Logic
The selection process begins by parsing the selector string using css-what and grouping the resulting tokens. The system distinguishes between "plain" selectors (standard CSS) and "filtered" selectors (those containing positional pseudos).
Selector Execution Flow
When a query is initiated via select, the engine splits the work. Plain selectors are compiled and executed in a single pass using compileToken. Filtered selectors undergo a recursive process where the engine resolves the selector up to the positional pseudo, filters the resulting set, and then continues with any remaining selector parts.
The diagram illustrates how the wrapper differentiates between standard CSS and positional logic during the selection lifecycle.
Sources: src/index.ts:208-232, src/index.ts:250-280
Positional Pseudo-Selectors
The system implements a specific set of positional pseudos that operate on the current set of matched elements. Unlike standard CSS pseudos (like :nth-child) which operate relative to siblings in the DOM, these operate on the flattened array of elements matched by the preceding part of the selector.
Supported Positional Pseudos
| Pseudo | Description | Implementation Logic |
|---|---|---|
:first | Selects the first element. | Returns element at index 0. |
:last | Selects the last element. | Returns element at length - 1. |
:eq(n) | Selects element at index n. | Supports negative indices (from end). |
:lt(n) | Selects elements with index less than n. | Uses slice(0, n). |
:gt(n) | Selects elements with index greater than n. | Uses slice(n + 1). |
:even | Selects even-indexed elements. | index % 2 === 0. |
:odd | Selects odd-indexed elements. | index % 2 === 1. |
Sources: README.md:14-25, src/index.ts:85-115
Implementation of filterByPosition
The filterByPosition function handles the array manipulation for these pseudos. For index-based selectors (eq, nth), it handles bounds checking and negative index resolution.
case "eq": {
return Number.isFinite(position) &&
Math.abs(position) < elements.length
? [
position < 0
? elements[elements.length + position]
: elements[position],
]
: [];
}
Sources: src/index.ts:98-107
Traversal and Context Management
The wrapper architecture must handle complex scenarios where a positional selector is followed by further traversals (e.g., div:first + p). When a traversal is detected following a filter, the engine adjusts the query context.
Context Preparation
If a sibling traversal follows a positional filter, the engine uses prepareContext to include siblings of the matched elements in the search space. It also sets a rootFunc in the options to ensure that subsequent traversals do not escape the subtree defined by the current result set.
This sequence shows the interaction when a selector requires context preparation due to trailing traversals after a positional match.
Sources: src/index.ts:285-325, src/index.ts:360-375
API Surface
The library exposes several high-level functions that mirror the standard css-select API but with enhanced positional support.
| Function | Signature | Purpose |
|---|---|---|
select | (selector, root, options, limit) | Finds all elements matching the selector. |
filter | (selector, elements, options) | Filters a list of nodes by selector. |
is | (element, selector, options) | Checks if a single element matches a selector. |
some | (elements, selector, options) | Checks if at least one element in a list matches. |
Sources: src/index.ts:51-54, src/index.ts:68-71, src/index.ts:126-129, src/index.ts:200-205, src/index.spec.ts:40-60
Integration with External Libraries
The architecture relies heavily on the cheerio ecosystem and low-level DOM utilities:
css-select: Used for standard CSS compilation and re-exporting base pseudo-selectors.css-what: Used for parsing selector strings into structured tokens.domutils: Used for DOM traversal (find,getChildren), uniqueness sorting (uniqueSort), and element identification (isTag).domhandler: Provides the node and element type definitions.
Sources: package.json:62-67, src/index.ts:1-15
cheerio-select effectively extends the capabilities of css-select by providing a recursive execution model that interleaves standard CSS selection with array-based positional filtering, enabling the complex query patterns required for jQuery-compatible environments.