{"id":16319,"library":"css-tree","title":"CSSTree: CSS AST Parser, Walker, Generator, and Lexer","description":"CSSTree is a comprehensive toolkit for processing CSS, providing a fast and detailed parser to transform CSS source into an Abstract Syntax Tree (AST), a walker for efficient AST traversal, a generator to serialize AST back into CSS, and a lexer for syntax validation and matching based on W3C specifications and browser implementations. The current stable version is 3.2.1, with frequent patch and minor releases indicating active development. It stands out for its performance (benchmarked as one of the fastest), spec compliance, detailed AST format with adjustable parsing levels, and inherent error tolerance by wrapping malformed content in `Raw` nodes instead of discarding it. It also leverages `mdn/data` for robust syntax validation, making it suitable for complex CSS analysis and source-to-source transformations.","status":"active","version":"3.2.1","language":"javascript","source_language":"en","source_url":"https://github.com/csstree/csstree","tags":["javascript","css","ast","tokenizer","parser","walker","lexer","generator","utils"],"install":[{"cmd":"npm install css-tree","lang":"bash","label":"npm"},{"cmd":"yarn add css-tree","lang":"bash","label":"yarn"},{"cmd":"pnpm add css-tree","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"Primary function to convert CSS string into an AST. For older CommonJS environments, `require` is used, but ESM is preferred since v2.1.0.","wrong":"const parse = require('css-tree').parse;","symbol":"parse","correct":"import { parse } from 'css-tree';"},{"note":"Used to convert an AST back into a CSS string. Ensure the AST adheres to the CSSTree format.","wrong":"const generate = require('css-tree').generate;","symbol":"generate","correct":"import { generate } from 'css-tree';"},{"note":"Provides a robust mechanism for traversing the AST, useful for transformations or inspections. It accepts an AST and an options object for controlling traversal behavior.","wrong":"const walk = require('css-tree').walk;","symbol":"walk","correct":"import { walk } from 'css-tree';"},{"note":"The Lexer class is exposed for advanced syntax validation and matching. It uses `mdn/data` for definitions and can be configured with custom CSS-wide keywords.","wrong":"const Lexer = require('css-tree').Lexer;","symbol":"Lexer","correct":"import { Lexer } from 'css-tree';"}],"quickstart":{"code":"import { parse, generate, walk } from 'css-tree';\n\nconst cssInput = `\n  .container {\n    display: flex;\n    gap: 10px; /* New in CSS, handled by CSSTree */\n    background: linear-gradient(to right, #f00, #00f);\n    @container (min-width: 400px) {\n      .item {\n        font-size: 1.2em;\n      }\n    }\n  }\n  @media (max-width: 600px) {\n    .container { flex-direction: column; }\n  }\n`;\n\ntry {\n  const ast = parse(cssInput, { \n    positions: true, // Include source location info\n    onParseError: (error, fallbackNode) => {\n      console.warn(`Parsing error at ${error.line}:${error.column}: ${error.message}`);\n      // Optionally, return fallbackNode or throw to stop parsing\n    }\n  });\n\n  console.log('Original AST (partial):', ast.children.first.type, ast.children.first.loc);\n\n  // Example: Walk the AST to find all `Declaration` nodes and log their properties\n  let declarationCount = 0;\n  walk(ast, {\n    visit: 'Declaration',\n    enter: (node) => {\n      declarationCount++;\n      console.log(`  Declaration: ${node.property}: ${generate(node.value)}`);\n    }\n  });\n  console.log(`Total declarations found: ${declarationCount}`);\n\n  // Modify the AST, e.g., change `gap` to `margin` for demonstration\n  walk(ast, {\n    visit: 'Declaration',\n    enter: (node) => {\n      if (node.property === 'gap') {\n        node.property = 'margin'; // Simple AST modification\n      }\n    }\n  });\n\n  const modifiedCss = generate(ast);\n  console.log('\\nModified CSS:\\n', modifiedCss);\n\n} catch (error) {\n  console.error('An unexpected error occurred:', error);\n}","lang":"typescript","description":"This quickstart demonstrates parsing CSS into an AST, traversing the AST to inspect nodes (e.g., declarations), modifying the AST, and then generating the modified CSS string. It also shows error handling during parsing."},"warnings":[{"fix":"Review AST traversal and manipulation logic to gracefully handle new `AtRule` types introduced in CSS specifications. Use `walk` with `visit` options to target specific node types or ensure `enter`/`leave` handlers are robust to unknown node types.","message":"CSSTree v3.0.0 introduced support for new CSS at-rules like `@container`, `@starting-style`, `@scope`, `@position-try`, and `@layer`. While generally backward compatible for existing CSS, these additions expand the AST structure. Code that relies on a fixed set of AST node types or specific traversal patterns might need adjustments to account for these new nodes. Ensure your code handles new `AtRule` types if traversing or transforming the AST.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Refactor any custom logic for handling nested CSS or `@media` inside rules, as CSSTree now natively supports these structures. The AST will reflect `NestingSelector` nodes and altered `DeclarationList` behavior within blocks.","message":"Starting with v2.3.0, CSSTree added comprehensive support for CSS Nesting, including `NestingSelector` for `&` and changes in how `@media` inside a `Rule`'s block is parsed. This fundamentally alters the AST structure for nested CSS, particularly within `@media` blocks inside rules, which now parse as `Declaration` first. If your tooling processed nested CSS with workarounds, these may now conflict with CSSTree's native support.","severity":"breaking","affected_versions":">=2.3.0"},{"fix":"If your code expects `Array` methods on `children` properties of AST nodes (e.g., `node.children.map()`), ensure you pass `{ list: false }` to the `parse()` method: `parse(css, { list: false })`. Otherwise, use `List` methods like `node.children.toArray()` or iterate using `forEach`.","message":"The `parse()` method's `list` option (added in v3.2.0) defaults to `true`, producing `List` instances for children nodes (e.g., `SelectorList`, `Block`). If you prefer standard JavaScript arrays for children nodes, you must explicitly set `list: false`. Not doing so might lead to unexpected behavior if your code expects array methods directly on children properties.","severity":"gotcha","affected_versions":">=3.2.0"},{"fix":"When traversing the AST, explicitly check for and handle `Raw` nodes. You can inspect their `value` property for the raw string content. If validation is important, use the `Lexer#validate()` method (enhanced in v3.0.1 with an `errors` array) or implement custom logic to process or report these `Raw` nodes.","message":"CSSTree parser is tolerant to errors by design, meaning it doesn't throw away malformed content but wraps it in a special `Raw` node type. While this prevents crashes, it means you might encounter `Raw` nodes in your AST if the input CSS is invalid. Ignoring these `Raw` nodes could lead to incomplete or incorrect transformations.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Either convert the `List` to an array using `node.children.toArray().map(...)` or set the `list` option to `false` when parsing: `parse(css, { list: false })`.","cause":"The `children` property of AST nodes is a `List` instance by default (since v3.2.0's `list: true` default), not a standard JavaScript array.","error":"TypeError: node.children.map is not a function"},{"fix":"Review the CSS input for missing semicolons, unbalanced curly brackets, or other syntax errors. If using `parse()` with `onParseError`, inspect the `error` object for `line` and `column` to pinpoint the exact location of the issue. The parser is tolerant, so this error is more likely from strict validation or subsequent processing.","cause":"This error typically originates from the `Lexer` during validation or strict parsing, indicating a fundamental structural issue in the CSS input that violates W3C syntax rules.","error":"Error: CSS syntax error: Expecting a semicolon or a right curly bracket"},{"fix":"Update your AST processing logic (e.g., `walk` callbacks) to recognize and handle new `AtRule` types. You can use a `default` case in a switch statement or `else` clause to log unknown types or skip them gracefully.","cause":"Your AST traversal or transformation code might be encountering new CSS at-rules (e.g., `@container`, `@scope`) that were added in later CSSTree versions or CSS specifications, and your logic doesn't explicitly handle them.","error":"Unknown node type: SomeNewAtRule"}],"ecosystem":"npm"}