Transforms CSS declaration values and at-rule parameters into abstract syntax trees with traversal API
npx @tessl/cli install tessl/npm-postcss-value-parser@4.2.0PostCSS Value Parser transforms CSS declaration values and at-rule parameters into abstract syntax trees (AST) with a simple traversal API. It provides comprehensive CSS value parsing for build tools, PostCSS plugins, and applications requiring detailed CSS value analysis.
npm install postcss-value-parserconst valueParser = require('postcss-value-parser');For ES modules:
import valueParser from 'postcss-value-parser';const valueParser = require('postcss-value-parser');
// Parse a CSS value
const cssValue = 'rgba(233, 45, 66, .5) no-repeat center/contain';
const parsed = valueParser(cssValue);
// Walk through all nodes
parsed.walk(function(node) {
if (node.type === 'function' && node.value === 'rgba') {
// Transform rgba() to hex
const values = node.nodes.filter(n => n.type === 'word').map(n => n.value);
node.type = 'word';
node.value = '#E92D42';
}
});
// Convert back to CSS string
console.log(parsed.toString()); // "#E92D42 no-repeat center/contain"PostCSS Value Parser is built around a tree-based parsing approach:
Main parser function that converts CSS values into traversable node trees.
/**
* Parse a CSS value into a series of nodes
* Can be called as function or constructor
* @param value - The CSS value string to parse
* @returns ParsedValue instance with nodes array and methods
*/
function valueParser(value: string): ParsedValue;
/**
* Constructor form of the parser
* @param value - The CSS value string to parse
* @returns ParsedValue instance
*/
new valueParser(value: string): ParsedValue;
interface ParsedValue {
/** Array of parsed nodes */
nodes: Node[];
/** Convert parsed nodes back to CSS string */
toString(): string;
/** Walk all parsed nodes with callback function */
walk(callback: WalkCallback, bubble?: boolean): this;
}Usage Examples:
// Parse background shorthand - both patterns work
const parsed1 = valueParser('url(bg.jpg) no-repeat 50% 75%');
const parsed2 = new valueParser('url(bg.jpg) no-repeat 50% 75%');
console.log(parsed1.nodes.length); // 7 nodes
// Parse function with parameters
const rgba = valueParser('rgba(255, 0, 128, 0.5)');
console.log(rgba.nodes[0].type); // 'function'
console.log(rgba.nodes[0].value); // 'rgba'
console.log(rgba.nodes[0].nodes.length); // 7 (4 values + 3 dividers)Traverse the parsed node tree with visitor callbacks, supporting both depth-first and reverse traversal.
/**
* Walk all parsed nodes, applying callback function
* @param callback - Visitor function called for each node
* @param bubble - When true, traverse inside-out instead of outside-in
* @returns this (chainable)
*/
walk(callback: WalkCallback, bubble?: boolean): this;
/**
* Static walk function for node arrays
* @param nodes - Array of nodes to walk
* @param callback - Visitor function called for each node
* @param bubble - When true, traverse inside-out instead of outside-in
*/
function walk(nodes: Node[], callback: WalkCallback, bubble?: boolean): void;
interface WalkCallback {
/**
* @param node - Current node being visited
* @param index - Index of node in parent's nodes array
* @param nodes - Parent's complete nodes array
* @returns Returning false prevents traversal of descendant nodes (only when bubble=false)
*/
(node: Node, index: number, nodes: Node[]): void | boolean;
}Usage Examples:
// Find and modify all function calls
parsed.walk(function(node) {
if (node.type === 'function') {
console.log(`Found function: ${node.value}`);
// Modify function name
node.value = 'new-' + node.value;
}
});
// Shallow walk (don't traverse into functions)
parsed.walk(function(node) {
console.log(node.type);
if (node.type === 'function') {
return false; // Skip function contents
}
}, false);
// Reverse traversal (inside-out)
parsed.walk(function(node) {
console.log(node.value);
}, true);Convert parsed node trees back to CSS strings with optional custom stringification.
/**
* Convert parsed nodes back to CSS string
* @returns Reconstructed CSS value string
*/
toString(): string;
/**
* Static stringify function for nodes
* @param nodes - Node or array of nodes to stringify
* @param custom - Optional custom stringifier callback
* @returns CSS string representation
*/
function stringify(nodes: Node | Node[], custom?: CustomStringifierCallback): string;
interface CustomStringifierCallback {
/**
* @param node - Node to stringify
* @returns Custom string representation, or undefined to use default
*/
(node: Node): string | undefined;
}Usage Examples:
// Basic stringification
const cssString = parsed.toString();
// Custom stringification
const customCss = valueParser.stringify(parsed.nodes, function(node) {
if (node.type === 'function' && node.value === 'rgb') {
// Convert rgb() to hex
return '#FF0000';
}
// Return undefined to use default stringification
});Parse CSS values containing numbers and units into separate components.
/**
* Parse CSS dimension into numeric and unit parts
* @param value - CSS dimension string (e.g., "2rem", "100px", "1.5em")
* @returns Dimension object with number and unit, or false if parsing fails
*/
function unit(value: string): Dimension | false;
interface Dimension {
/** Numeric part as string (preserves original precision) */
number: string;
/** Unit part as string (empty string for unitless numbers) */
unit: string;
}Usage Examples:
// Parse various dimensions
console.log(valueParser.unit('2rem')); // { number: '2', unit: 'rem' }
console.log(valueParser.unit('100px')); // { number: '100', unit: 'px' }
console.log(valueParser.unit('1.5em')); // { number: '1.5', unit: 'em' }
console.log(valueParser.unit('50')); // { number: '50', unit: '' }
console.log(valueParser.unit('auto')); // false (not a dimension)
// Use in node walking
parsed.walk(function(node) {
if (node.type === 'word') {
const dimension = valueParser.unit(node.value);
if (dimension && dimension.unit === 'px') {
// Convert px to rem
const remValue = parseFloat(dimension.number) / 16;
node.value = remValue + 'rem';
}
}
});All parsed CSS values are represented as trees of typed nodes. Each node has common properties plus type-specific properties.
interface BaseNode {
/** Node type identifier */
type: string;
/** The node's characteristic value */
value: string;
/** Start position in original CSS string (inclusive) */
sourceIndex: number;
/** End position in original CSS string (exclusive) */
sourceEndIndex: number;
}
/** Mixin interface for nodes that can be unclosed */
interface ClosableNode {
/** True if the node was not properly closed in CSS */
unclosed?: true;
}
/** Mixin interface for nodes with adjacent whitespace */
interface AdjacentAwareNode {
/** Whitespace before the node content */
before: string;
/** Whitespace after the node content */
after: string;
}Represents keywords, quantities, and hex colors.
interface WordNode extends BaseNode {
type: 'word';
/** The word value (e.g., 'no-repeat', '20px', '#e6e6e6') */
value: string;
}Examples: no-repeat, 20px, 75%, 1.5, #e6e6e6, auto
Represents quoted string values.
interface StringNode extends BaseNode, ClosableNode {
type: 'string';
/** Text content without quotes */
value: string;
/** Quote character used (" or ') */
quote: '"' | "'";
}Examples: "Arial" in font-family: "Arial", 'image.png' in background: url('image.png')
Represents CSS functions with their arguments.
interface FunctionNode extends BaseNode, ClosableNode, AdjacentAwareNode {
type: 'function';
/** Function name (e.g., 'rgb', 'url', 'calc') */
value: string;
/** Child nodes representing function arguments */
nodes: Node[];
}Examples: rgba(255, 0, 0, 0.5), url(image.jpg), calc(100% - 20px)
Special Cases:
url() functions with unquoted arguments are parsed differently than quoted ones(min-width: 700px)) are parsed as functions with empty valuecalc() functions have special handling for / and * operatorsRepresents divider characters with surrounding whitespace.
interface DivNode extends BaseNode, AdjacentAwareNode {
type: 'div';
/** Divider character (',', '/', or ':') */
value: ',' | '/' | ':';
}Examples: , in 1s, 2s, 3s, / in 10px / 20px, : in (min-width: 700px)
Represents whitespace used as separators.
interface SpaceNode extends BaseNode {
type: 'space';
/** Whitespace characters */
value: string;
}Examples: Space in border: 1px solid black
Represents CSS comments.
interface CommentNode extends BaseNode, ClosableNode {
type: 'comment';
/** Comment content without /* and */ delimiters */
value: string;
}Examples: /* comment */ becomes { type: 'comment', value: ' comment ' }
Represents Unicode range descriptors used in @font-face rules.
interface UnicodeRangeNode extends BaseNode {
type: 'unicode-range';
/** Unicode range value (e.g., 'U+0025-00FF') used in @font-face rules */
value: string;
}Examples: U+0025-00FF, U+4E00-9FFF
type Node =
| WordNode
| StringNode
| FunctionNode
| DivNode
| SpaceNode
| CommentNode
| UnicodeRangeNode;Access utility functions directly on the main parser function.
/** CSS dimension parsing utility */
valueParser.unit: (value: string) => Dimension | false;
/** Static tree walking utility */
valueParser.walk: (nodes: Node[], callback: WalkCallback, bubble?: boolean) => void;
/** Static stringification utility */
valueParser.stringify: (nodes: Node | Node[], custom?: CustomStringifierCallback) => string;