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

utilities.mddocs/

Utility Functions

Collection of utility functions for CSS identifier, string, and URL encoding/decoding, plus AST manipulation helpers.

Capabilities

Identifier Utilities

Functions for encoding and decoding CSS identifiers with proper escaping:

namespace ident {
  /**
   * Encodes a string as a CSS identifier with proper escaping
   * @param str - String to encode as identifier
   * @returns Properly escaped CSS identifier
   */
  function encode(str: string): string;

  /**
   * Decodes a CSS identifier, unescaping escape sequences
   * @param str - CSS identifier to decode
   * @returns Decoded string
   */
  function decode(str: string): string;
}

Usage Examples:

import { ident } from 'css-tree';

// Encode identifiers with special characters
console.log(ident.encode('my-class'));      // "my-class"
console.log(ident.encode('2nd-item'));      // "\\32 nd-item"
console.log(ident.encode('with space'));    // "with\\ space"
console.log(ident.encode('with:colon'));    // "with\\:colon"

// Decode escaped identifiers
console.log(ident.decode('\\32 nd-item'));  // "2nd-item"
console.log(ident.decode('with\\ space'));  // "with space"
console.log(ident.decode('with\\:colon'));  // "with:colon"

// Safe class name generation
function safeClassName(name) {
  return ident.encode(name.replace(/[^a-zA-Z0-9-_]/g, '-'));
}

String Utilities

Functions for encoding and decoding CSS string literals:

namespace string {
  /**
   * Encodes a string as a CSS string literal with proper quotes and escaping
   * @param str - String to encode
   * @param apostrophe - Use single quotes instead of double quotes
   * @returns Properly quoted and escaped CSS string
   */
  function encode(str: string, apostrophe?: boolean): string;

  /**
   * Decodes a CSS string literal, removing quotes and unescaping sequences
   * @param str - CSS string literal to decode
   * @returns Decoded string content
   */
  function decode(str: string): string;
}

Usage Examples:

import { string } from 'css-tree';

// Encode strings with special characters
console.log(string.encode('Hello World'));           // "\"Hello World\""
console.log(string.encode('Hello "World"'));         // "\"Hello \\\"World\\\"\""
console.log(string.encode("Hello 'World'", true));   // "'Hello \\'World\\''"
console.log(string.encode('Line 1\nLine 2'));        // "\"Line 1\\A Line 2\""

// Decode string literals
console.log(string.decode('"Hello World"'));         // "Hello World"
console.log(string.decode('"Hello \\"World\\""'));   // "Hello \"World\""
console.log(string.decode("'Hello \\'World\\''"));   // "Hello 'World'"
console.log(string.decode('"Line 1\\A Line 2"'));    // "Line 1\nLine 2"

// Generate content property values
function generateContent(text) {
  return `content: ${string.encode(text)};`;
}

URL Utilities

Functions for encoding and decoding CSS URL values:

namespace url {
  /**
   * Encodes a URL string as a complete CSS url() function
   * @param str - URL string to encode
   * @returns Complete CSS url() function with encoded URL
   */
  function encode(str: string): string;

  /**
   * Decodes a URL from CSS url() function content
   * @param str - URL content from url() function
   * @returns Decoded URL string
   */
  function decode(str: string): string;
}

Usage Examples:

import { url } from 'css-tree';

// Encode URLs with special characters
console.log(url.encode('image.png'));                    // "url(image.png)"
console.log(url.encode('image with spaces.png'));       // "url(image\\ with\\ spaces.png)"
console.log(url.encode('path/to/image.png'));           // "url(path/to/image.png)"
console.log(url.encode('https://example.com/img.png')); // "url(https://example.com/img.png)"

// Decode URL content
console.log(url.decode('image.png'));                   // "image.png"
console.log(url.decode('image\\ with\\ spaces.png'));   // "image with spaces.png"
console.log(url.decode('path/to/image.png'));          // "path/to/image.png"

// Generate background-image values
function generateBackgroundImage(imagePath) {
  return `background-image: url(${url.encode(imagePath)});`;
}

Name Analysis Functions

Functions for analyzing CSS property and keyword names:

/**
 * Analyzes a CSS keyword name for vendor prefixes and custom properties
 * @param name - Keyword name to analyze
 * @returns Analysis result with prefix information
 */
function keyword(name: string): KeywordAnalysis;

/**
 * Analyzes a CSS property name for vendor prefixes, hacks, and custom properties
 * @param name - Property name to analyze
 * @returns Analysis result with detailed information
 */
function property(name: string): PropertyAnalysis;

interface KeywordAnalysis {
  /** Base name without prefixes */
  basename: string;
  /** Original name */
  name: string;
  /** Vendor prefix if present */
  prefix?: string;
  /** Vendor identifier (webkit, moz, ms, o) */
  vendor?: string;
  /** Whether it's a custom property (starts with --) */
  custom: boolean;
}

interface PropertyAnalysis {
  /** Base name without prefixes or hacks */
  basename: string;
  /** Original name */
  name: string;
  /** CSS hack character if present */
  hack?: string;
  /** Vendor identifier (webkit, moz, ms, o) */
  vendor?: string;
  /** Vendor prefix (-webkit-, -moz-, etc.) */
  prefix?: string;
  /** Whether it's a custom property (starts with --) */
  custom: boolean;
}

Usage Examples:

import { keyword, property } from 'css-tree';

// Analyze keywords
console.log(keyword('inherit'));           // { basename: 'inherit', name: 'inherit', custom: false }
console.log(keyword('-webkit-fill'));      // { basename: 'fill', name: '-webkit-fill', prefix: '-webkit-', vendor: 'webkit', custom: false }
console.log(keyword('--custom-value'));    // { basename: '--custom-value', name: '--custom-value', custom: true }

// Analyze properties
console.log(property('color'));            // { basename: 'color', name: 'color', custom: false }
console.log(property('-webkit-transform')); // { basename: 'transform', name: '-webkit-transform', prefix: '-webkit-', vendor: 'webkit', custom: false }
console.log(property('*zoom'));            // { basename: 'zoom', name: '*zoom', hack: '*', custom: false }
console.log(property('--main-color'));     // { basename: '--main-color', name: '--main-color', custom: true }

// Group properties by vendor
function groupPropertiesByVendor(properties) {
  const groups = { standard: [], webkit: [], moz: [], ms: [], o: [] };
  
  properties.forEach(prop => {
    const analysis = property(prop);
    const group = analysis.vendor || 'standard';
    groups[group].push(prop);
  });
  
  return groups;
}

AST Manipulation Utilities

Core utilities for AST cloning and conversion:

/**
 * Deep clones an AST node with all children and properties
 * @param node - AST node to clone
 * @returns Deep clone of the node
 */
function clone(node: CssNode): CssNode;

/**
 * Converts AST with List children to plain objects with arrays
 * @param ast - AST to convert
 * @returns Plain object representation
 */
function toPlainObject(ast: CssNode): object;

/**
 * Converts plain object AST to use List instances for children
 * @param ast - Plain object AST
 * @returns AST with List children
 */
function fromPlainObject(ast: object): CssNode;

Usage Examples:

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

const ast = parse('.example { color: red; }');

// Clone AST for safe modification
const clonedAst = clone(ast);

// Modify clone without affecting original
walk(clonedAst, (node) => {
  if (node.type === 'Identifier' && node.name === 'red') {
    node.name = 'blue';
  }
});

console.log(generate(ast));        // ".example{color:red}"
console.log(generate(clonedAst));  // ".example{color:blue}"

// Convert to plain object for serialization
const plainObject = toPlainObject(ast);
const jsonString = JSON.stringify(plainObject, null, 2);

// Convert back from plain object
const restoredAst = fromPlainObject(JSON.parse(jsonString));
console.log(generate(restoredAst)); // ".example{color:red}"

// Deep clone with custom modifications
function cloneAndModify(ast, modifications) {
  const cloned = clone(ast);
  
  walk(cloned, (node) => {
    if (modifications[node.type]) {
      modifications[node.type](node);
    }
  });
  
  return cloned;
}

Advanced Utility Patterns

Complex utility functions for common CSS processing tasks:

// Normalize vendor prefixes
function normalizeVendorPrefixes(ast) {
  const normalized = clone(ast);
  
  walk(normalized, {
    Declaration: (node) => {
      const analysis = property(node.property.name);
      if (analysis.vendor) {
        // Store original vendor-prefixed version
        node.vendorPrefixed = node.property.name;
        // Use standard name
        node.property.name = analysis.basename;
      }
    }
  });
  
  return normalized;
}

// Extract custom properties
function extractCustomProperties(ast) {
  const customProps = [];
  
  walk(ast, {
    Declaration: (node) => {
      const analysis = property(node.property.name);
      if (analysis.custom) {
        customProps.push({
          name: node.property.name,
          value: generate(node.value),
          node: clone(node)
        });
      }
    }
  });
  
  return customProps;
}

// Validate identifiers in selectors
function validateSelectors(ast) {
  const issues = [];
  
  walk(ast, {
    ClassSelector: (node) => {
      try {
        ident.decode(node.name);
      } catch (error) {
        issues.push({
          type: 'InvalidClassSelector',
          name: node.name,
          message: error.message
        });
      }
    },
    IdSelector: (node) => {
      try {
        ident.decode(node.name);
      } catch (error) {
        issues.push({
          type: 'InvalidIdSelector',
          name: node.name,
          message: error.message
        });
      }
    }
  });
  
  return issues;
}

// Safe string generation for content property
function generateContentValue(text, useDoubleQuotes = true) {
  try {
    return string.encode(text, !useDoubleQuotes);
  } catch (error) {
    // Fallback to basic escaping
    const escaped = text.replace(/["'\\]/g, '\\$&');
    return useDoubleQuotes ? `"${escaped}"` : `'${escaped}'`;
  }
}

// URL resolution helper
function resolveUrls(ast, baseUrl) {
  const resolved = clone(ast);
  
  walk(resolved, {
    Url: (node) => {
      try {
        const urlValue = url.decode(node.value);
        if (!urlValue.match(/^https?:\/\//)) {
          // Resolve relative URL
          const resolvedUrl = new URL(urlValue, baseUrl).href;
          node.value = url.encode(resolvedUrl);
        }
      } catch (error) {
        console.warn('Failed to resolve URL:', node.value);
      }
    }
  });
  
  return resolved;
}