postcss-selector-parser
A CSS selector parser and AST toolkit for building PostCSS plugins that inspect, transform, and rewrite selectors.
Repository Health
Technical Analysis
postcss-selector-parser converts CSS selector strings into a structured, mutable abstract syntax tree, and serializes that tree back into valid CSS — losslessly preserving whitespace and comments by default. It ships as the selector-parsing engine behind many of the PostCSS ecosystem’s plugins, handling the full selector grammar: combinators, pseudo-classes and pseudo-elements, attribute selectors, id/class/tag selectors, nesting (&), comments, and non-standard syntax like /deep/.
Consumers walk the resulting tree with typed visitor methods (walkClasses, walkAttributes, walkPseudos, etc.), mutate nodes in place, and call toString() or processSync() to get back a selector string — either the original formatting or a normalized, whitespace-collapsed form. A guarded maximum nesting depth (default 256, added after CVE-2026-9358) protects the recursive parse/stringify routines from stack-overflow denial-of-service on adversarial input.
What You Get
- A full CSS selector parser producing an inspectable node tree (Root, Selector, Tag, ClassName, Id, Attribute, Pseudo, Combinator, Comment, Nesting, String, Universal)
- Typed walk*/each* traversal methods for every node kind, plus a generic walk() with early-exit support
- Synchronous and Promise-based processing APIs (processSync/transformSync/astSync vs process/transform/ast)
- Lossless round-tripping that preserves original whitespace, comments and raw values, with an opt-in lossy/normalized output mode
- Node constructors (parser.attribute(), parser.className(), parser.pseudo(), etc.) for programmatically building new selector fragments
- A configurable maxNestingDepth guard against pathological or adversarial selector nesting
Common Use Cases
- Writing a PostCSS plugin that needs to inspect or rewrite selectors (adding vendor prefixes, scoping classes for CSS Modules, rewriting :global()/:local())
- Linting or auditing CSS selectors for disallowed patterns (universal selectors, deep combinators, specific pseudo-classes)
- Build tooling that needs to safely parse untrusted or third-party CSS selectors without risking stack overflow on maliciously nested input
- Generating or transforming selectors programmatically (renaming classes, namespacing ids, stripping comments) for CSS-in-JS or CSS Modules pipelines
- Static analysis tools that need an accurate selector AST rather than regex-based selector parsing
Under The Hood
Architecture
The library is layered as tokenizer → parser → AST → processor. src/tokenize.js turns a selector string into a character-code token stream (src/tokenTypes.js), src/parser.js consumes that stream to build a tree of node classes defined in src/selectors/ (Root, Selector, Tag, ClassName, Attribute, Pseudo, Combinator, Comment, Nesting, String, Universal), and a shared Container base class implements the walk*/each* traversal methods every composite node inherits. src/processor.js is the public orchestration layer: it wraps _root/_run/_runSync around the parser and the tree’s own toString(), exposing sync and Promise-based variants (processSync/process, astSync/ast, transformSync/transform) that optionally write the transformed selector back onto a postcss.Rule. This separation means the tokenizer and grammar can evolve independently of the public processing API, and the recursive walk/serialize path is the one piece bounded by maxNestingDepth to prevent stack overflow on adversarial input.
Tech Stack
The source is authored in TypeScript/modern JS (src/index.ts plus .js implementation files) and compiled to dist/ via tsc, with postcss-selector-parser.d.ts hand-maintained as the public type surface. Runtime dependencies are deliberately minimal: cssesc for CSS-safe escaping and util-deprecate for deprecation warnings. Linting and formatting run on oxlint/oxfmt (Rust-based tooling) rather than ESLint/Prettier, tests run on Node’s built-in node:test runner against the compiled dist/, and CI (GitHub Actions) runs the full suite across an ubuntu/windows × lts/latest Node matrix.
Code Quality
The src/__tests__/ directory holds close to 30 .mjs test files, each scoped to one selector construct (attributes, combinators, pseudos, escapes, namespaces, nesting, recursion, lossy round-tripping, sourceIndex, exceptions), giving comprehensive grammar coverage. The coverage script enforces hard thresholds (94% lines, 94% branches, 96% functions) via --experimental-test-coverage, and typecheck runs tsc --strict against the public .d.ts and its accompanying .test.ts to guard the type surface. Public Processor methods carry JSDoc, and API.md explicitly narrows the supported surface, discouraging reliance on undocumented internals.
API Design
The public surface is intentionally small: one factory function (parser(transform, options)) returning a Processor with three symmetric sync/async pairs (process/processSync, transform/transformSync, ast/astSync). Losslessness is the default behavior rather than an opt-in, so a naive processSync(str) round-trips input unchanged — a design choice that avoids surprising output for the common case. Every node kind gets both a dedicated walkX traversal method and a matching parser.x() constructor, keeping the mental model uniform across the whole node hierarchy, and getting started requires no configuration beyond the transform callback.
Used by 6 apps in this directory
AFFiNE
Productivity · Project Management · Note Taking
Write, draw, and plan in one infinite canvas — the open-source alternative to Notion and Miro that keeps your data yours.
CodeSandbox
Code Editors · Developer Tools
Instantly ready browser-based IDE that runs full npm dependency resolution and transpilation entirely client-side, with no server needed.
Documenso
Digital Signiture
Self-hosted, open-source DocuSign alternative with legally binding PDF signatures, multi-party workflows, and a full REST and tRPC API.
HyperFrames
AI Development · AI Design Tools
Turn plain HTML and CSS into deterministic, pixel-perfect MP4 videos — authored by humans or AI agents, rendered by headless Chrome and FFmpeg.
Keep
Devops · Automation · Monitoring
The open-source AIOps and alert management platform that unifies 130+ monitoring tools into a single pane of glass with AI-powered correlation, deduplication, and workflow automation.
Wiki.js
Knowledge Management · Collaboration
A modern, self-hosted wiki platform built on Node.js with a rich plugin ecosystem for authentication, search, storage, and rendering that adapts to any team's infrastructure.