Hone logo
Hone
Problems

CSS Selector Parser in JavaScript

Building a CSS selector parser is a fundamental task in web development, often used in libraries for DOM manipulation, testing, and more. This challenge asks you to implement a simplified CSS selector parser in JavaScript that can identify which elements in a hypothetical DOM match a given selector string. Successfully completing this challenge will give you a deeper understanding of how CSS selectors work and how to parse strings effectively.

Problem Description

You are tasked with creating a JavaScript function parseSelector(selector) that takes a CSS selector string as input and returns a function. This returned function, when called with a DOM element as input, should return true if the element matches the selector, and false otherwise. The parser should support the following selectors:

  • Tag selectors: e.g., div, p, h1
  • ID selectors: e.g., #myId
  • Class selectors: e.g., .myClass
  • Combinators:
    • Descendant selector: e.g., div p (p elements anywhere inside div elements)
    • Child selector: e.g., div > p (p elements that are direct children of div elements)

The returned matching function should check if a given DOM element matches the parsed selector. For simplicity, assume the DOM element has the following properties:

  • tagName: A string representing the element's tag name (e.g., "DIV", "P", "H1"). Case-insensitive.
  • id: A string representing the element's ID.
  • className: A string representing the element's class name.
  • children: An array of child DOM elements.

Expected Behavior:

The parseSelector function should return a function that accurately determines if a given DOM element matches the selector. The matching function should be case-insensitive when comparing tag names.

Examples

Example 1:

Input: parseSelector('div')
Output: function(element) { return element.tagName.toUpperCase() === 'DIV'; }
Explanation: The returned function checks if the element's tag name is "DIV" (case-insensitive).

Example 2:

Input: parseSelector('#myId')
Output: function(element) { return element.id === 'myId'; }
Explanation: The returned function checks if the element's ID is "myId".

Example 3:

Input: parseSelector('.myClass')
Output: function(element) { return element.className === 'myClass'; }
Explanation: The returned function checks if the element's class name is "myClass".

Example 4:

Input: parseSelector('div p')
Output: function(element) {
  for (const child of element.children) {
    if (child.tagName.toUpperCase() === 'P') {
      return true;
    }
  }
  return false;
}
Explanation: The returned function checks if any of the element's children have a tag name of "P".

Example 5:

Input: parseSelector('div > p')
Output: function(element) {
  for (const child of element.children) {
    if (child.tagName.toUpperCase() === 'P') {
      return true;
    }
  }
  return false;
}
Explanation: The returned function checks if any of the element's *direct* children have a tag name of "P".

Constraints

  • The selector string will only contain valid CSS selector characters (letters, numbers, periods, hashes, spaces, and greater-than signs).
  • The input selector string will not be empty.
  • The matching function should be efficient enough to handle reasonably sized DOM elements (up to 100 children).
  • The parseSelector function should handle selectors with multiple parts correctly (e.g., div > .myClass p). While full CSS selector support is not required, the combination of tag, class, and ID selectors with combinators is expected.

Notes

  • You don't need to implement a full CSS parser. Focus on the core selectors and combinators mentioned above.
  • Consider using recursion to handle nested selectors.
  • Think about how to break down the selector string into its constituent parts.
  • The DOM element properties (tagName, id, className, children) are guaranteed to exist and be of the correct type.
  • Error handling for invalid selectors is not required. Assume the input is always a valid selector string.
  • Prioritize clarity and readability in your code. A well-structured solution is more important than extreme optimization.
Loading editor...
javascript