postcss-selector-parser

A CSS selector parser and AST toolkit for building PostCSS plugins that inspect, transform, and rewrite selectors.

Library
npm
v7.1.6
215 stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
67 /100 Good
Development Activity 56
Maintenance 56
Community 76
Maturity 60
Momentum 20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
82 /100 Excellent
Architecture 82
Code Quality 85
Innovation 85
Learning Curve 75

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 7 apps in this directory

TypeScript
82%
Other

AFFiNE

Collaboration · Note Taking · Productivity

73,040

Write, draw, and plan in one infinite canvas — the open-source alternative to Notion and Miro that keeps your data yours.

View details
91
Repo Health
87
Technical
67
Dependency
Built with
TypeScript 82%
Rust 11%
Updated 5 days ago
JavaScript
90%
Other

CodeSandbox

Code Editors · Developer Tools

13,650

Instantly ready browser-based IDE that runs full npm dependency resolution and transpilation entirely client-side, with no server needed.

View details
67
Repo Health
76
Technical
62
Dependency
Built with
JavaScript 90%
Updated 3 weeks ago
TypeScript
92%
AGPL 3.0

Documenso

Digital Signiture

15,224

Self-hosted, open-source DocuSign alternative with legally binding PDF signatures, multi-party workflows, and a full REST and tRPC API.

View details
93
Repo Health
79
Technical
68
Dependency
Built with
TypeScript 92%
Updated 4 days ago
TypeScript
87%
Apache 2.0

HyperFrames

AI Design Tools · AI Development

53,695

Turn plain HTML and CSS into deterministic, pixel-perfect MP4 videos — authored by humans or AI agents, rendered by headless Chrome and FFmpeg.

View details
84
Repo Health
83
Technical
65
Dependency
Built with
TypeScript 87%
JavaScript 12%
Updated 4 days ago
Python
64%
Other

Keep

Automation · Devops · Monitoring

12,359

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.

View details
89
Repo Health
79
Technical
66
Dependency
Built with
Python 64%
TypeScript 36%
Updated 1 weeks ago
TypeScript
91%
MIT

OpenClaw

AI Agents · AI Assistants

390,670

An open-source AI assistant that runs on your own hardware and meets you in Discord, Slack, WhatsApp, iMessage, Telegram, and 20+ other channels, with native apps for every major platform.

View details
88
Repo Health
88
Technical
68
Dependency
Built with
TypeScript 91%
Updated 4 days ago
Vue
47%
AGPL 3.0

Wiki.js

Collaboration · Knowledge Management

28,977

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.

View details
79
Repo Health
67
Technical
60
Dependency
Built with
Vue 47%
JavaScript 44%
Updated 4 days ago

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers