b_values is a type-safe, bidirectional CSS declaration parser and generator, built from the ground up with a focus on architectural purity, robust error handling, and developer experience. It translates CSS declaration strings into a strict, well-defined Intermediate Representation (IR) and can generate CSS strings back from that IR.
It is built with TypeScript and Zod to provide strong compile-time and run-time guarantees about the shape of your CSS data...
This library is designed to be more than just a string-splitter. It is built on a few core principles:
- Bidirectional & Lossless (in spirit): The system can parse CSS into a structured IR and generate it back out. While it canonicalizes syntax (e.g.,
rgb(0,0,0)might becomergb(0 0 0)), it preserves the semantic meaning. - Type-Safe IR: The shape of every CSS property's value is defined by a Zod schema. This eliminates entire classes of bugs and makes the data structure self-documenting and verifiable.
- Resilient by Design: When parsing lists (e.g., multiple background layers), a failure in one item does not prevent other valid items from being parsed.
- Rich Error Reporting: Parse and generate operations never throw. They return a
Resultobject containing either the value or a detailed array ofissues(errors or warnings), complete with contextual messages and suggestions. - First-Class Symbolic Values: CSS values like
var(...)andcalc(...)are not treated as opaque strings. They are parsed into their own structured IR nodes, allowing for deep introspection and manipulation. - Architecturally Sound: The system uses a clear Orchestrator Pattern to separate concerns. High-level orchestrators handle universal logic (like CSS-wide keywords) and delegate property-specific logic to specialized parsers.
The primary entry point is parseDeclaration from the @b/declarations package.
import{parseDeclaration}from"@b/declarations";constcss="background-color: red;";constresult=parseDeclaration(css);if(result.ok){console.log(result.value);// {// property: 'background-color',// ir: { kind: 'named', name: 'red' }// }}Use generateDeclaration to turn an IR object back into a CSS string.
import{generateDeclaration}from"@b/declarations";constdeclarationIR={property: "background-color"asconst,ir: {kind: "named",name: "red"},};constresult=generateDeclaration(declarationIR);if(result.ok){console.log(result.value);// "background-color: red"}b_values excels at parsing complex, modern CSS.
import{parseDeclaration}from"@b/declarations";constcss='background-image: url("stars.png"), linear-gradient(to right, #f00, oklch(50% 0.25 20));';constresult=parseDeclaration(css);// The resulting `ir` would look like this (simplified):// {// property: 'background-image',// ir: {// kind: 'list',// values: [// { kind: 'url', url: 'stars.png' },// {// kind: 'gradient',// gradient: {// kind: 'linear',// direction: { kind: 'to-side', value: 'right' },// colorStops: [// { color: { kind: 'hex', value: '#f00' }},// {// color: {// kind: 'oklch',// l: { kind: 'literal', value: 50, unit: '%' },// c: { kind: 'literal', value: 0.25 },// h: { kind: 'literal', value: 20 }// }// }// ]// }// }// ]// }// }The library never throws on invalid input, instead returning meticulous error reports.
import{parseDeclaration}from"@b/declarations";// CSS with a syntax error (three values for background-size is invalid)constcss="background-size: 50% 100px 200px;";constresult=parseDeclaration(css);console.log(result.ok);// falseif(!result.ok){console.log(result.issues);// [// {// "code": "invalid-syntax",// "severity": "error",// "message": "Unexpected content after a valid value, likely a missing comma. Unparsed: \"200px\""// }// ]}The project is a monorepo with a strict separation of concerns between packages.
| Package | Responsibility |
|---|---|
@b/types | Defines all reusable component value schemas (e.g., <image>, <color>, <bg-size>) and the Result system. |
@b/keywords | Defines the vocabulary of CSS. Provides Zod schemas for all keyword sets (cssWide, namedColor, etc.). |
@b/units | Defines the vocabulary of CSS units (px, deg, vw, etc.). |
@b/parsers | Contains low-level component parsers that turn css-tree AST nodes into b_types IR (e.g., parseColorNode). |
@b/generators | Contains low-level component generators that turn b_types IR back into CSS strings (e.g., generateColor). |
@b/declarations | The main engine. Orchestrates everything. Defines full property IRs, registers properties, and provides the top-level parseDeclaration and generateDeclaration functions. |
@b/utils | Shared utility functions for string manipulation, AST traversal, and validation helpers. |
A fundamental concept is the separation of a reusable CSS component value from the final property IR.
- Component Value (
CssValuein@b/types): A low-level, reusable building block. For example, the<bg-size>type is defined in@b/typesbecause it's a reusable component used by bothbackground-sizeandmask-size. - Property IR (
...IRin@b/declarations): The final, top-level schema for a specific property. For example,BackgroundSizeIRis defined in@b/declarations. It orchestrates the<bg-size>component type into a final structure that includes a list (kind: 'list') and the ability to be a CSS-wide keyword (kind: 'keyword').
This separation ensures that common CSS value types are defined once and reused everywhere, while property-specific logic remains cleanly encapsulated.
Install Dependencies:
npm install
Run Tests:
npm test
MIT