CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-postcss-selector-parser

Selector parser with built in methods for working with selector strings.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

node-manipulation.mddocs/

Node Manipulation

Base methods available on all AST nodes for manipulation, navigation, and tree modification. Includes specialized container methods for nodes that can have children.

Capabilities

Base Node Interface

Common properties and methods available on all AST nodes.

/**
 * Base interface for all AST nodes
 */
interface Base {
  /** Node type identifier */
  type: string;
  /** Parent container node */
  parent: Container;
  /** Node value/content */
  value: string;
  /** Whitespace configuration */
  spaces: Spaces;
  /** Source location information */
  source?: NodeSource;
  /** Index in source string */
  sourceIndex: number;
  /** Raw whitespace before node */
  rawSpaceBefore: string;
  /** Raw whitespace after node */
  rawSpaceAfter: string;
  /** Raw values for precise output control */
  raws?: NodeRaws;
  
  /**
   * Remove this node from its parent
   * @returns The removed node
   */
  remove(): Node;
  
  /**
   * Replace this node with other nodes
   * @param nodes - Nodes to replace with
   * @returns This node
   */
  replaceWith(...nodes: Node[]): Node;
  
  /**
   * Get the next sibling node
   * @returns Next sibling or undefined
   */
  next(): Node | undefined;
  
  /**
   * Get the previous sibling node
   * @returns Previous sibling or undefined
   */
  prev(): Node | undefined;
  
  /**
   * Clone this node
   * @param opts - Override options
   * @returns Cloned node
   */
  clone(opts?: {[key: string]: any}): this;
  
  /**
   * Check if node includes character at given position
   * @param line - 1-based line number
   * @param column - 1-based column number
   * @returns Whether node is at position
   */
  isAtPosition(line: number, column: number): boolean | undefined;
  
  /**
   * Set property with escaped value
   * @param name - Property name
   * @param value - Unescaped value
   * @param valueEscaped - Escaped value
   */
  setPropertyAndEscape(name: string, value: any, valueEscaped: string): void;
  
  /**
   * Set property without escaping
   * @param name - Property name
   * @param value - Value (both escaped and unescaped)
   */
  setPropertyWithoutEscape(name: string, value: any): void;
  
  /**
   * Append to property with escaped value
   * @param name - Property name
   * @param value - Unescaped value
   * @param valueEscaped - Escaped value
   */
  appendToPropertyAndEscape(name: string, value: any, valueEscaped: string): void;
  
  /**
   * Convert node to string representation
   * @returns String representation
   */
  toString(): string;
}

interface NodeRaws {
  /** Raw value as it appeared in source */
  value?: string;
  /** Raw spacing information */
  spaces?: {
    before?: string;
    after?: string;
  };
}

Usage Examples:

const parser = require('postcss-selector-parser');

const ast = parser().astSync('.class1, .class2');
const firstSelector = ast.first;
const classNode = firstSelector.first;

// Navigate nodes
const nextNode = classNode.next();
const prevNode = classNode.prev();

// Clone node
const clonedNode = classNode.clone();

// Remove node
classNode.remove();

// Replace node
const newClass = parser.className({ value: 'new-class' });
classNode.replaceWith(newClass);

Container Interface

Methods available on nodes that can contain children (Root, Selector, Pseudo).

/**
 * Interface for nodes that can contain children
 */
interface Container extends Base {
  /** Array of child nodes */
  nodes: Node[];
  
  /**
   * Append a child node
   * @param node - Node to append
   * @returns This container
   */
  append(node: Node): this;
  
  /**
   * Prepend a child node
   * @param node - Node to prepend
   * @returns This container
   */
  prepend(node: Node): this;
  
  /**
   * Get child node at index
   * @param index - Child index
   * @returns Child node
   */
  at(index: number): Node;
  
  /**
   * Get most specific node at line/column position
   * @param line - 1-based line number
   * @param column - 1-based column number
   * @returns Node at position
   */
  atPosition(line: number, column: number): Node;
  
  /**
   * Get index of child node
   * @param child - Child node
   * @returns Index of child
   */
  index(child: Node): number;
  
  /** First child node */
  readonly first: Node;
  
  /** Last child node */
  readonly last: Node;
  
  /** Number of child nodes */
  readonly length: number;
  
  /**
   * Remove specific child node
   * @param child - Child to remove
   * @returns This container
   */
  removeChild(child: Node): this;
  
  /**
   * Remove all child nodes
   * @returns This container
   */
  removeAll(): this;
  
  /**
   * Remove all child nodes (alias for removeAll)
   * @returns This container
   */
  empty(): this;
  
  /**
   * Insert nodes after existing node
   * @param oldNode - Reference node
   * @param newNode - Node to insert
   * @param restNodes - Additional nodes to insert
   * @returns This container
   */
  insertAfter(oldNode: Node, newNode: Node, ...restNodes: Node[]): this;
  
  /**
   * Insert nodes before existing node
   * @param oldNode - Reference node
   * @param newNode - Node to insert
   * @param restNodes - Additional nodes to insert
   * @returns This container
   */
  insertBefore(oldNode: Node, newNode: Node, ...restNodes: Node[]): this;
}

Usage Examples:

const parser = require('postcss-selector-parser');

const root = parser.root();
const selector = parser.selector();

// Append children
selector.append(parser.tag({ value: 'div' }));
selector.append(parser.className({ value: 'container' }));
root.append(selector);

// Access children
const firstChild = selector.first;  // div
const lastChild = selector.last;    // .container
const childCount = selector.length; // 2

// Insert nodes
const id = parser.id({ value: 'main' });
selector.insertBefore(selector.first, id);
// Result: #main div.container

// Remove children
selector.removeChild(selector.last);
selector.empty(); // Remove all children

Container Iteration Methods

Methods for iterating over and traversing container nodes.

interface Container {
  /**
   * Iterate over direct children
   * @param callback - Function called for each child
   * @returns False if iteration was stopped
   */
  each(callback: (node: Node, index: number) => boolean | void): boolean | undefined;
  
  /**
   * Walk all descendant nodes
   * @param callback - Function called for each descendant
   * @returns False if traversal was stopped
   */
  walk(callback: (node: Node, index: number) => boolean | void): boolean | undefined;
  
  /**
   * Walk all attribute nodes
   * @param callback - Function called for each attribute
   * @returns False if traversal was stopped
   */
  walkAttributes(callback: (node: Attribute) => boolean | void): boolean | undefined;
  
  /**
   * Walk all class nodes
   * @param callback - Function called for each class
   * @returns False if traversal was stopped
   */
  walkClasses(callback: (node: ClassName) => boolean | void): boolean | undefined;
  
  /**
   * Walk all combinator nodes
   * @param callback - Function called for each combinator
   * @returns False if traversal was stopped
   */
  walkCombinators(callback: (node: Combinator) => boolean | void): boolean | undefined;
  
  /**
   * Walk all comment nodes
   * @param callback - Function called for each comment
   * @returns False if traversal was stopped
   */
  walkComments(callback: (node: Comment) => boolean | void): boolean | undefined;
  
  /**
   * Walk all ID nodes
   * @param callback - Function called for each ID
   * @returns False if traversal was stopped
   */
  walkIds(callback: (node: Identifier) => boolean | void): boolean | undefined;
  
  /**
   * Walk all nesting nodes
   * @param callback - Function called for each nesting node
   * @returns False if traversal was stopped
   */
  walkNesting(callback: (node: Nesting) => boolean | void): boolean | undefined;
  
  /**
   * Walk all pseudo nodes
   * @param callback - Function called for each pseudo
   * @returns False if traversal was stopped
   */
  walkPseudos(callback: (node: Pseudo) => boolean | void): boolean | undefined;
  
  /**
   * Walk all tag nodes
   * @param callback - Function called for each tag
   * @returns False if traversal was stopped
   */
  walkTags(callback: (node: Tag) => boolean | void): boolean | undefined;
  
  /**
   * Walk all universal nodes
   * @param callback - Function called for each universal
   * @returns False if traversal was stopped
   */
  walkUniversals(callback: (node: Universal) => boolean | void): boolean | undefined;
}

Usage Examples:

const parser = require('postcss-selector-parser');

const ast = parser().astSync('.btn, #header > .nav .item');

// Iterate over selectors
ast.each((selector, index) => {
  console.log(`Selector ${index}:`, selector.toString());
});

// Walk all nodes
ast.walk((node, index) => {
  console.log(`Node ${index}:`, node.type, node.value);
});

// Walk specific node types
ast.walkClasses(classNode => {
  console.log('Class:', classNode.value);
  // Outputs: btn, nav, item
});

ast.walkIds(idNode => {
  console.log('ID:', idNode.value);
  // Outputs: header
});

// Stop traversal early
ast.walkUniversals(universalNode => {
  console.log('Universal selector found');
  universalNode.remove(); // Remove all * selectors
});

ast.walkTags(tagNode => {
  if (tagNode.value === 'div') {
    return false; // Stop walking
  }
});

Container Array Methods

Array-like methods for working with child nodes.

interface Container {
  /**
   * Split children based on predicate
   * @param callback - Predicate function
   * @returns Tuple of [matching, non-matching] nodes
   */
  split(callback: (node: Node) => boolean): [Node[], Node[]];
  
  /**
   * Map over children
   * @param callback - Mapping function
   * @returns Array of mapped values
   */
  map<T>(callback: (node: Node) => T): T[];
  
  /**
   * Reduce children to single value
   * @param callback - Reducer function
   * @param initialValue - Initial value
   * @returns Reduced value
   */
  reduce<T>(
    callback: (
      previousValue: T,
      currentValue: Node,
      currentIndex: number,
      array: readonly Node[]
    ) => T,
    initialValue?: T
  ): T;
  
  /**
   * Test if all children match predicate
   * @param callback - Test function
   * @returns True if all children match
   */
  every(callback: (node: Node) => boolean): boolean;
  
  /**
   * Test if some children match predicate
   * @param callback - Test function
   * @returns True if any children match
   */
  some(callback: (node: Node) => boolean): boolean;
  
  /**
   * Filter children by predicate
   * @param callback - Filter function
   * @returns Array of matching children
   */
  filter(callback: (node: Node) => boolean): Node[];
  
  /**
   * Sort children by comparison function
   * @param callback - Comparison function
   * @returns Array of sorted children
   */
  sort(callback: (nodeA: Node, nodeB: Node) => number): Node[];
}

Usage Examples:

const parser = require('postcss-selector-parser');

const selector = parser().astSync('div.btn#main').first;

// Map node values
const values = selector.map(node => node.value);
// Result: ['div', 'btn', 'main']

// Filter by type
const classes = selector.filter(node => node.type === 'class');

// Check conditions
const hasId = selector.some(node => node.type === 'id');
const allHaveValues = selector.every(node => node.value);

// Split by type
const [tags, others] = selector.split(node => node.type === 'tag');

// Sort by value
const sorted = selector.sort((a, b) => a.value.localeCompare(b.value));

Types

interface Spaces {
  before: string;
  after: string;
  [spaceType: string]: string | Partial<SpaceAround> | undefined;
}

interface SpaceAround {
  before: string;
  after: string;
}

interface NodeSource {
  start?: { line: number; column: number };
  end?: { line: number; column: number };
}

Install with Tessl CLI

npx tessl i tessl/npm-postcss-selector-parser

docs

index.md

node-constructors.md

node-manipulation.md

parser-processor.md

type-guards.md

tile.json