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

type-guards.mddocs/

Type Guards

Runtime type checking functions for identifying and validating AST node types. Essential for safely working with the parsed AST and implementing type-specific logic.

Capabilities

General Node Validation

Core functions for validating nodes and their capabilities.

/**
 * Check if value is a valid AST node
 * @param node - Value to check
 * @returns True if value is a node
 */
function isNode(node: any): boolean;

/**
 * Check if node is a container (can have children)
 * @param node - Node to check
 * @returns True if node is Root, Selector, or Pseudo
 */
function isContainer(node: any): boolean;

/**
 * Check if node supports namespaces
 * @param node - Node to check
 * @returns True if node is Attribute or Tag
 */
function isNamespace(node: any): boolean;

Usage Examples:

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

const ast = parser().astSync('.class, #id');
const node = ast.first.first;

// Check if it's a valid node
if (parser.isNode(node)) {
  console.log('Valid node:', node.type);
}

// Check if it can contain children
if (parser.isContainer(node)) {
  console.log('Can contain children');
  node.walk(child => {
    console.log('Child:', child.type);
  });
}

// Check if it supports namespaces
if (parser.isNamespace(node)) {
  console.log('Supports namespaces');
  console.log('Namespace:', node.namespace);
}

Container Type Guards

Functions for identifying specific container node types.

/**
 * Check if node is a Root container
 * @param node - Node to check
 * @returns True if node is Root
 */
function isRoot(node: any): boolean;

/**
 * Check if node is a Selector container
 * @param node - Node to check
 * @returns True if node is Selector
 */
function isSelector(node: any): boolean;

/**
 * Check if node is a Pseudo container
 * @param node - Node to check
 * @returns True if node is Pseudo
 */
function isPseudo(node: any): boolean;

Usage Examples:

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

const ast = parser().astSync('.class:hover');

// Check root
if (parser.isRoot(ast)) {
  console.log('This is the root container');
  console.log('Selectors:', ast.nodes.length);
}

// Check selector
const firstChild = ast.first;
if (parser.isSelector(firstChild)) {
  console.log('This is a selector');
  console.log('Components:', firstChild.nodes.length);
}

// Check pseudo
const pseudo = firstChild.last;
if (parser.isPseudo(pseudo)) {
  console.log('This is a pseudo selector');
  console.log('Value:', pseudo.value);
}

Leaf Node Type Guards

Functions for identifying specific leaf node types that cannot contain children.

/**
 * Check if node is an Attribute selector
 * @param node - Node to check
 * @returns True if node is Attribute
 */
function isAttribute(node: any): boolean;

/**
 * Check if node is a ClassName selector
 * @param node - Node to check
 * @returns True if node is ClassName
 */
function isClassName(node: any): boolean;

/**
 * Check if node is a Combinator
 * @param node - Node to check
 * @returns True if node is Combinator
 */
function isCombinator(node: any): boolean;

/**
 * Check if node is a Comment
 * @param node - Node to check
 * @returns True if node is Comment
 */
function isComment(node: any): boolean;

/**
 * Check if node is an Identifier (ID selector)
 * @param node - Node to check
 * @returns True if node is Identifier
 */
function isIdentifier(node: any): boolean;

/**
 * Check if node is a Nesting selector
 * @param node - Node to check
 * @returns True if node is Nesting
 */
function isNesting(node: any): boolean;

/**
 * Check if node is a String literal
 * @param node - Node to check
 * @returns True if node is String
 */
function isString(node: any): boolean;

/**
 * Check if node is a Tag selector
 * @param node - Node to check
 * @returns True if node is Tag
 */
function isTag(node: any): boolean;

/**
 * Check if node is a Universal selector
 * @param node - Node to check
 * @returns True if node is Universal
 */
function isUniversal(node: any): boolean;

Usage Examples:

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

const ast = parser().astSync('div.class#id[href] > * + /* comment */');
const selector = ast.first;

// Walk through nodes and identify types
selector.walk(node => {
  if (parser.isTag(node)) {
    console.log('Tag:', node.value);
  } else if (parser.isClassName(node)) {
    console.log('Class:', node.value);
  } else if (parser.isIdentifier(node)) {
    console.log('ID:', node.value);
  } else if (parser.isAttribute(node)) {
    console.log('Attribute:', node.attribute);
  } else if (parser.isCombinator(node)) {
    console.log('Combinator:', node.value);
  } else if (parser.isUniversal(node)) {
    console.log('Universal selector');
  } else if (parser.isComment(node)) {
    console.log('Comment:', node.value);
  }
});

Pseudo Type Guards

Specialized functions for distinguishing between pseudo-classes and pseudo-elements.

/**
 * Check if node is specifically a pseudo-element
 * @param node - Node to check
 * @returns True if node is a pseudo-element
 */
function isPseudoElement(node: any): boolean;

/**
 * Check if node is specifically a pseudo-class
 * @param node - Node to check
 * @returns True if node is a pseudo-class
 */
function isPseudoClass(node: any): boolean;

Usage Examples:

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

const ast = parser().astSync('.btn:hover::before:first-letter');
const selector = ast.first;

selector.walkPseudos(pseudo => {
  if (parser.isPseudoElement(pseudo)) {
    console.log('Pseudo-element:', pseudo.value);
    // Outputs: ::before, :first-letter
  } else if (parser.isPseudoClass(pseudo)) {
    console.log('Pseudo-class:', pseudo.value);
    // Outputs: :hover
  }
});

// Specific pseudo-element detection
const pseudos = [':before', ':after', '::before', '::after', ':first-letter', ':first-line'];
pseudos.forEach(pseudoValue => {
  const node = parser.pseudo({ value: pseudoValue });
  console.log(`${pseudoValue} is pseudo-element:`, parser.isPseudoElement(node));
});

Type-Safe Processing

Using type guards for safe node processing and transformation.

Usage Examples:

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

// Transform function using type guards
const transform = selectors => {
  selectors.walk(node => {
    // Remove universal selectors
    if (parser.isUniversal(node)) {
      node.remove();
      return;
    }
    
    // Convert all IDs to classes
    if (parser.isIdentifier(node)) {
      const className = parser.className({ value: node.value });
      node.replaceWith(className);
      return;
    }
    
    // Add namespace to tags
    if (parser.isTag(node)) {
      node.namespace = 'app';
      return;
    }
    
    // Process attributes
    if (parser.isAttribute(node)) {
      if (node.attribute === 'class') {
        // Convert [class="value"] to .value
        if (node.operator === '=' && node.value) {
          const className = parser.className({ value: node.value });
          node.replaceWith(className);
        }
      }
      return;
    }
  });
};

const processor = parser(transform);
const result = processor.processSync('*#header.nav[class="btn"]');
// Result: app|#header.nav.btn

Advanced Type Guard Usage

Combining type guards for complex logic and validation.

Usage Examples:

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

// Function to analyze selector complexity
function analyzeSelector(selectorString) {
  const ast = parser().astSync(selectorString);
  const stats = {
    selectors: 0,
    tags: 0,
    classes: 0,
    ids: 0,
    attributes: 0,
    pseudoClasses: 0,
    pseudoElements: 0,
    combinators: 0,
    hasNamespaces: false,
    hasComments: false
  };
  
  ast.walk(node => {
    if (parser.isSelector(node)) {
      stats.selectors++;
    } else if (parser.isTag(node)) {
      stats.tags++;
      if (parser.isNamespace(node) && node.namespace) {
        stats.hasNamespaces = true;
      }
    } else if (parser.isClassName(node)) {
      stats.classes++;
    } else if (parser.isIdentifier(node)) {
      stats.ids++;
    } else if (parser.isAttribute(node)) {
      stats.attributes++;
    } else if (parser.isPseudoClass(node)) {
      stats.pseudoClasses++;
    } else if (parser.isPseudoElement(node)) {
      stats.pseudoElements++;
    } else if (parser.isCombinator(node)) {
      stats.combinators++;
    } else if (parser.isComment(node)) {
      stats.hasComments = true;
    }
  });
  
  return stats;
}

// Usage
const stats = analyzeSelector('div.nav#main[data-id] > .item:hover::before');
console.log(stats);
// { selectors: 1, tags: 1, classes: 2, ids: 1, attributes: 1, 
//   pseudoClasses: 1, pseudoElements: 1, combinators: 1, ... }

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