Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 31 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,18 @@
> [!WARNING]
> This is a very experimental CSS parser. Expect several bugs and inconveniences!

**High-performance CSS parser optimized for static analysis and formatting**
**High-performance CSS parser built for static analysis and tooling**

Built for speed and efficiency, this parser handles large CSS files with minimal memory overhead and blazing-fast parse times. Designed with a data-oriented architecture using a single contiguous memory arena for zero allocations during parsing.
Parses large CSS files in microseconds with a fixed-size memory arena — no garbage collection pressure, no per-node allocations, no surprises. If you're building a formatter, linter, or analysis tool and need raw speed with precise source locations, this is built for that.

This parser was heavily influenced by [CSSTree](https://github.com/csstree/csstree), one of the most robust CSS parsers available. Some of the parsing mechanics are taken from CSSTree, as well as some of the performance mechanics, but a lot of things are very different which is why this isn't a direct fork and there is very little overlap in API's.
Heavily influenced by [CSSTree](https://github.com/csstree/csstree). Some parsing mechanics are shared, but the memory model, architecture, and API are fundamentally different — not a fork.

## Features

- **Modern CSS support** - CSS Nesting, `:is()`, `:where()`, `:has()`, `@layer`, `@container`
- **Error recovery** - Continues parsing on malformed CSS
- **Location tracking** - Line, column, offset, and length for all nodes
- **Performance** - Low memory usage and excellent parsing speed
- **Small bundle size** - Fast download and installation in any environment
- **Full modern CSS** — CSS Nesting, `:is()`, `:where()`, `:has()`, `@layer`, `@container`
- **Error-tolerant** — keeps parsing through malformed input; one bad rule won't kill the file
- **Precise source locations** — line, column, offset, and length on every node
- **Tiny footprint** — tree-shakeable subparsers; as small as 278 bytes gzipped, < 16 kB kB worst case

## Installation

Expand Down Expand Up @@ -59,20 +58,36 @@ for (const rule of ast) {

## Performance

- **Small install size** (~200kB)
- **Zero allocations during parsing** - all memory allocated upfront based on real world heuristics, which also helps prevent garbage collection running often
- **Cache-friendly data layout** - contiguous memory for sequential access powered by concepts of Data Oriented Design
- **First-class comment and location support** - while still being performant because analysis requires constant access to lines and columns
- **No syntax validation** - focusing only on the raw data we can skip expensive syntax files and MDN data syncs
- **Zero allocations during parsing** — memory is reserved upfront using real-world heuristics; the GC never runs mid-parse
- **Cache-friendly layout** — all nodes live in a single contiguous arena, making sequential access fast
- **Location tracking with no penalty** — full line, column, and offset data without slowing the parser down
- **No syntax validation** — skipping spec checks and MDN data means nothing gets in the way of speed

### Bundle sizes

All sizes are minified and bundled with dependencies. Import only what you need — bundlers will tree-shake the rest.

| Import | Description | Minified | Gzip |
| ------------------------------------------------- | ---------------------------- | -------- | ------- |
| `@projectwallace/css-parser` | Full parser (all subparsers) | 68.9 kB | 15.5 kB |
| `@projectwallace/css-parser/parse` | CSS stylesheet parser | 62.2 kB | 13.3 kB |
| `@projectwallace/css-parser/parse-atrule-prelude` | At-rule prelude parser | 35.4 kB | 8.4 kB |
| `@projectwallace/css-parser/parse-selector` | Selector parser | 37.7 kB | 8.9 kB |
| `@projectwallace/css-parser/parse-anplusb` | An+B syntax parser | 26.1 kB | 6.6 kB |
| `@projectwallace/css-parser/parse-declaration` | Declaration parser | 28.3 kB | 7.3 kB |
| `@projectwallace/css-parser/parse-value` | Value parser | 25.2 kB | 6.6 kB |
| `@projectwallace/css-parser/parse-dimension` | Dimension parser | 0.4 kB | 0.3 kB |
| `@projectwallace/css-parser/tokenizer` | Tokenizer | 9.8 kB | 2.4 kB |

## Documentation

See [API.md](./API.md) for complete documentation of all parser functions and options.
See [API.md](./API.md) for complete documentation of all parser functions and nodes.

## Non-goals

- **No syntax validation** - this parser does not try to validate your CSS structure. Everything can be anything
- **No custom syntax support** - we're leaving the era of CSS preprocessors so we only focus on CSS
- **No syntax validation** — CSS structure is your responsibility; the parser accepts anything valid or not
- **No preprocessor syntax** — Sass, Less, and Stylus are out of scope; this parser targets plain CSS only
- **Tree operations** - Manipulating the AST is not within scope of this library

## License

Expand Down
2 changes: 1 addition & 1 deletion knip.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"ignore": ["/benchmark/**"],
"ignore": ["/benchmark/**", "test/build/**"],
"ignoreDependencies": [
"@projectwallace/preset-oxlint",
"bootstrap",
Expand Down
22 changes: 10 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,26 +88,24 @@
"devDependencies": {
"@projectwallace/preset-oxlint": "^0.0.10",
"@types/node": "^24.10.1",
"@vitest/coverage-v8": "^4.1.5",
"@vitest/coverage-v8": "^4.1.9",
"bootstrap": "^5.3.8",
"css-tree": "^3.1.0",
"knip": "^6.11.0",
"oxfmt": "^0.49.0",
"oxlint": "^1.62.0",
"postcss": "^8.5.6",
"publint": "^0.3.18",
"knip": "^6.18.0",
"oxfmt": "^0.56.0",
"oxlint": "^1.71.0",
"postcss": "^8.5.15",
"publint": "^0.3.21",
"tailwindcss": "^2.2.8",
"tinybench": "^6.0.1",
"tsdown": "^0.22.0",
"tinybench": "^6.0.2",
"tsdown": "^0.22.3",
"typescript": "^6.0.3",
"vitest": "^4.1.5"
"vite": "^8.0.16",
"vitest": "^4.1.9"
},
"engines": {
"pnpm": ">=11.0.0"
},
"packageManager": "pnpm@11.1.1",
"pnpm": {
"onlyBuiltDependencies": []
},
"issues": "https://github.com/projectwallace/css-parser/issues"
}
Loading
Loading