CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-stylis

A lightweight CSS preprocessor that provides CSS parsing, AST manipulation, vendor prefixing, and serialization capabilities.

Pending
Overview
Eval results
Files

serialization.mddocs/

Serialization and Stringification

Convert AST nodes back into CSS strings with customizable formatting and processing through callback-based serialization system.

Capabilities

Serialize Function

Core serialization function that traverses AST nodes and applies callback functions to generate CSS output.

/**
 * Convert AST nodes to CSS string using callback function
 * @param children - Array of AST node objects to serialize
 * @param callback - Function to process each node and generate CSS
 * @returns Serialized CSS string
 */
function serialize(children: object[], callback: function): string;

Usage Examples:

import { compile, serialize, stringify } from 'stylis';

// Basic serialization with default stringify
const ast = compile('h1 { color: red; }');
const css = serialize(ast, stringify);
console.log(css); // "h1{color:red;}"

// Custom serialization callback
const customCss = serialize(ast, (element, index, children, callback) => {
  if (element.type === 'rule') {
    return `/* Rule: ${element.props.join(', ')} */\n${stringify(element, index, children, callback)}`;
  }
  return stringify(element, index, children, callback);
});

// Serialization with middleware
import { middleware, prefixer } from 'stylis';
const processed = serialize(
  compile('div { display: flex; }'),
  middleware([prefixer, stringify])
);

Stringify Function

Default stringification middleware that converts AST nodes into standard CSS syntax.

/**
 * Default stringification middleware for AST nodes
 * @param element - AST node to stringify
 * @param index - Index of node in children array
 * @param children - Array of sibling nodes
 * @param callback - Recursive callback for child nodes
 * @returns CSS string for the element
 */
function stringify(element: object, index: number, children: object[], callback: function): string;

Behavior by Node Type:

  • LAYER: Returns empty string if no children, otherwise processes children
  • IMPORT/NAMESPACE/DECLARATION: Returns element.return or element.value
  • COMMENT: Returns empty string (comments are typically stripped)
  • KEYFRAMES: Returns @keyframes name { ...children... }
  • RULESET: Returns selector { ...children... } if selector is non-empty

Serialization Callback Interface

Custom serialization callbacks follow this interface:

/**
 * Serialization callback function interface
 * @param element - Current AST node being processed
 * @param index - Index of element in parent's children array
 * @param children - Array of sibling elements
 * @param callback - Recursive callback to process child elements
 * @returns CSS string output for this element
 */
interface SerializationCallback {
  (element: object, index: number, children: object[], callback: function): string;
}

Node Processing Examples

Custom Rule Processing

import { compile, serialize } from 'stylis';

const customProcessor = (element, index, children, callback) => {
  switch (element.type) {
    case 'rule':
      // Add custom attributes to selectors
      const selectors = element.props.map(selector => `${selector}[data-styled]`);
      return `${selectors.join(',')}{${serialize(element.children, callback)}}`;
    
    case 'decl':
      // Add !important to all declarations
      return `${element.props}:${element.children} !important;`;
    
    default:
      return serialize([element], callback);
  }
};

const styled = serialize(compile('.component { color: red; }'), customProcessor);

Minification Example

const minifier = (element, index, children, callback) => {
  if (element.type === 'comm') {
    return ''; // Strip comments
  }
  
  // Use default processing but remove extra whitespace
  const result = stringify(element, index, children, callback);
  return result.replace(/\s+/g, ' ').trim();
};

const minified = serialize(compile(`
  .component {
    padding: 20px;
    margin: 10px;
  }
`), minifier);

Debug Output Example

const debugSerializer = (element, index, children, callback) => {
  const indent = '  '.repeat(getDepth(element));
  const nodeInfo = `${indent}/* ${element.type}: ${element.value} */\n`;
  const nodeOutput = stringify(element, index, children, callback);
  return nodeInfo + nodeOutput;
};

function getDepth(element) {
  let depth = 0;
  let current = element.parent;
  while (current) {
    depth++;
    current = current.parent;
  }
  return depth;
}

Output Formatting Control

The serialization system provides full control over CSS output formatting:

Whitespace Control

  • Minified: Remove all unnecessary whitespace
  • Formatted: Add indentation and line breaks for readability
  • Compact: Single line with minimal spacing

Comment Handling

  • Preserve: Keep all comments in output
  • Strip: Remove all comments
  • Selective: Keep only specific comment types (e.g., license headers)

Property Formatting

  • Standard: property: value;
  • Expanded: property : value ; (with extra spacing)
  • Custom: Apply transformation functions to property-value pairs

Error Handling

The serialization system is designed to handle malformed AST gracefully:

  • Missing Properties: Uses fallback values or empty strings
  • Invalid Nodes: Skips invalid nodes or applies default processing
  • Circular References: Detects and breaks circular references in AST
  • Type Mismatches: Handles unexpected node types with default behavior

Serialization errors are typically non-fatal and result in partial CSS output rather than throwing exceptions.

Install with Tessl CLI

npx tessl i tessl/npm-stylis

docs

index.md

middleware.md

parser.md

serialization.md

tokenization.md

utilities.md

tile.json