or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

data-structures.mdgeneration.mdindex.mdparsing.mdtokenization.mdtraversal.mdutilities.mdvalidation.md
tile.json

generation.mddocs/

CSS Generation

Converts Abstract Syntax Trees back into CSS source code with configurable formatting and source map generation.

Capabilities

Generate Function

Converts an AST back to CSS source code with optional formatting and source map generation.

/**
 * Generates CSS source code from an Abstract Syntax Tree
 * @param ast - AST node to convert to CSS
 * @param options - Optional generation configuration
 * @returns CSS source code string
 */
function generate(ast: CssNode, options?: GenerateOptions): string;

interface GenerateOptions {
  /** Whether to generate source maps */
  sourceMap?: boolean;
  /** Output filename for source maps */
  file?: string;
  /** Custom node decoration handlers */
  decorateNode?: (handlers: DecorateHandlers) => void;
}

interface DecorateHandlers {
  [nodeType: string]: (node: CssNode, handlers: DecorateHandlers) => string;
}

Usage Examples:

import { parse, generate } from 'css-tree';

// Basic generation
const ast = parse('.example { color: red; }');
const css = generate(ast);
console.log(css); // ".example{color:red}"

// Generation with source maps
const cssWithSourceMap = generate(ast, {
  sourceMap: true,
  file: 'output.css'
});

// Custom node decoration
const formattedCss = generate(ast, {
  decorateNode: (handlers) => {
    // Add custom formatting for specific node types
    handlers.Rule = (node, handlers) => {
      return handlers.selector(node.prelude) + ' {\n  ' +
             handlers.block(node.block).replace(/;/g, ';\n  ') +
             '\n}';
    };
  }
});

Default Formatting

CSS Tree generates compact CSS by default, removing unnecessary whitespace:

const ast = parse(`
  .example {
    color: red;
    margin: 10px 0;
    background: linear-gradient(to bottom, #fff, #000);
  }
`);

const css = generate(ast);
// Output: ".example{color:red;margin:10px 0;background:linear-gradient(to bottom,#fff,#000)}"

Source Map Generation

Generate source maps to maintain connections between generated CSS and original source:

interface SourceMapResult {
  css: string;
  map: SourceMapGenerator;
}

// Enable source map generation
const result = generate(ast, {
  sourceMap: true,
  file: 'styles.css'
});

// Access source map data
if (result.map) {
  console.log(result.map.toString());
}

Custom Node Handlers

Customize how specific AST node types are converted to CSS:

const prettyCSS = generate(ast, {
  decorateNode: (handlers) => {
    // Customize rule formatting
    handlers.Rule = (node) => {
      const selector = generate(node.prelude);
      const declarations = generate(node.block);
      return `${selector} {\n  ${declarations.replace(/;/g, ';\n  ')}\n}`;
    };
    
    // Customize declaration formatting
    handlers.Declaration = (node) => {
      const property = generate(node.property);
      const value = generate(node.value);
      return `${property}: ${value}`;
    };
    
    // Customize function formatting
    handlers.Function = (node) => {
      const name = node.name;
      const args = generate(node.children);
      return `${name}(${args})`;
    };
  }
});

Generation Context

The generator automatically handles different CSS contexts and node types:

// Generate different CSS constructs
const stylesheet = generate(stylesheetAst);
const selector = generate(selectorAst);
const declaration = generate(declarationAst);
const value = generate(valueAst);
const mediaQuery = generate(mediaQueryAst);

// Generate partial AST nodes
csstree.walk(ast, (node) => {
  if (node.type === 'Declaration') {
    const declarationCSS = generate(node);
    console.log(declarationCSS); // "color: red"
  }
});

Advanced Generation Options

interface AdvancedGenerateOptions extends GenerateOptions {
  /** Custom formatting configuration */
  formatting?: {
    indent?: string;
    beforeOpenBrace?: string;
    afterOpenBrace?: string;
    beforeCloseBrace?: string;
    afterCloseBrace?: string;
    beforeSelector?: string;
    afterSelector?: string;
    beforeProperty?: string;
    afterProperty?: string;
    beforeValue?: string;
    afterValue?: string;
  };
}

Error Handling

The generator handles Raw nodes and malformed AST structures gracefully:

// Generate AST with Raw nodes (unparseable content)
const ast = parse('.example { color: red; invalid-syntax; }');
const css = generate(ast);
// Raw content is preserved in output

// Handle incomplete or modified AST
csstree.walk(ast, (node) => {
  if (node.type === 'Declaration' && node.property.name === 'color') {
    // Modify AST
    node.value = { type: 'Identifier', name: 'blue' };
  }
});
const modifiedCSS = generate(ast);

Performance Considerations

// For large ASTs, consider streaming or chunked generation
function generateInChunks(ast, chunkSize = 1000) {
  const chunks = [];
  let nodeCount = 0;
  
  csstree.walk(ast, (node) => {
    nodeCount++;
    if (nodeCount % chunkSize === 0) {
      // Process chunk
      chunks.push(generate(node));
    }
  });
  
  return chunks.join('');
}

// Reuse generator instance for multiple operations
const generator = csstree.fork({
  // Custom configuration
}).generate;

const css1 = generator(ast1);
const css2 = generator(ast2);

Integration with Other Tools

// Integration with PostCSS
const postcss = require('postcss');

function csstreeToPostCSS(ast) {
  const css = generate(ast);
  return postcss.parse(css);
}

// Integration with source map libraries
const { SourceMapConsumer } = require('source-map');

function generateWithDetailedMaps(ast) {
  const result = generate(ast, { sourceMap: true });
  return {
    css: result.css,
    map: new SourceMapConsumer(result.map.toString())
  };
}