npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

css-selector-inspector

v1.0.0

Published

Parse, validate, and inspect CSS selectors

Downloads

27

Readme

🔎 css-selector-inspector (CSI)

CSI is a complete spec-based CSS3 selector parser and utility written in JavaScript.

Features:

  • Parse and tokenize any valid CSS3 selector string, guaranteed!
    • Supports escaped characters, including escaped unicode code points
    • Properly handles all valid whitespace
    • Parses around comment blocks
  • Validate that a selector is well-formed
  • Calculate specificity level of each compound selector
  • Sort theoretical property declarations in proper cascading order based on selector specificity, origin (user or author stylesheet or inline), and !important directive
  • Normalize selector strings by parsing and reassembling the components in a deterministic manner
  • Escape raw values to use as CSS identifiers or strings

Table of Contents

Usage

Install CSI into your project:

npm install css-selector-inspector --save
import CSI from 'css-selector-inspector';

console.log(CSI.parse('div.content:last-child > p:not([aria-hidden])::before'));
/* output:
[
  {
    tokens: [
      {
        type: "typeSelector",
        namespace: null,
        name: "div",
        location: 0,
        raw: "div",
        specificityType: "d"
      },
      {
        type: "classSelector",
        name: "content",
        location: 3,
        raw: ".content",
        specificityType: "c"
      },
      {
        type: "pseudoClassSelector",
        name: "last-child",
        location: 11,
        raw: ":last-child",
        specificityType: "c",
        expression: null
      },
      {
        type: "childCombinator",
        location: 22,
        raw: " > ",
        specificityType: null
      },
      {
        type: "typeSelector",
        namespace: null,
        name: "p",
        location: 25,
        raw: "p",
        specificityType: "d"
      },
      {
        type: "negationSelector",
        tokens: [
          {
            namespace: null,
            name: "aria-hidden",
            location: 31,
            raw: "[aria-hidden]",
            specificityType: "c",
            type: "attributePresenceSelector"
          }
        ],
        location: 26,
        raw: ":not([aria-hidden])",
        specificityType: null
      },
      {
        name: "before",
        location: 45,
        raw: "::before",
        type: "pseudoElementSelector",
        specificityType: "d"
      }
    ],
    specificity: {
      a: 0,
      b: 0,
      c: 3,
      d: 3
    }
  }
]
 */

console.log(CSI.parse('html, /* comments are ok! */ *|body'));
/* output:
[
  {
    tokens: [
      {
        type: "typeSelector",
        namespace: null,
        name: "html",
        location: 0,
        raw: "html",
        specificityType: "d"
      }
    ],
    specificity: {
      a: 0,
      b: 0,
      c: 0,
      d: 1
    }
  },
  {
    tokens: [
      {
        type: "typeSelector",
        namespace: {
          type: "wildcard"
        },
        name: "body",
        location: 29,
        raw: "body",
        specificityType: "d"
      }
    ],
    specificity: {
      a: 0,
      b: 0,
      c: 0,
      d: 1
    }
  }
]

Objects

CSI

This is the main object containing static methods for most of the selector utilities.

Static Methods

parse()

Parse a string containing selectors (one or more separated by commas) into its component tokens.

Params

  • string selector - selector list string, excluding braces {}

Returns

array an array of Selector objects (even if there is only one selector)

Throws

  • Syntax error if the string cannot be parsed, usually providing the location of the first invalid portion
  • If the parsing results in multiple, differing results, an ambiguity error is thrown (please file an issue if this error is encountered)
isValid()

Determine if a selector string is syntactically valid. This is a convenience method if you don't care about the parsed result, and it will not throw an error if passed an invalid selector. This will not determine if the components are supported by a CSS implementation (e.g. if a particular pseudo class actually exists in any browser).

Params

  • string selector - selector list string, excluding braces {}

Returns

bool determination of whether the selector string appears to be syntactically valid

normalize()

Normalize a selector string by parsing and reassembling. Removes extraneous whitespace, unencodes unnecessary unicode escapes, removes comments, and normalizes nth formulas.

Params

  • string selector - selector list string, excluding braces {}

Returns

string normalized selector string

Throws

  • Uses parse(), so has the potential to throw errors due to invalid selector strings.
sort()

Sort selectors and/or theoretical properties based on the cascading precedence order. All arguments are internally converted to TheoreticalProperty objects for comparison purposes but are returned as the original passed object(s). Selectors/properties are sorted in precedence order from highest to lowest, meaning the first item in the resulting array is the property that would win out. For items that are otherwise equal based on precedence and specificity, the item passed latest will appear first in the resulting array.

Params

  • array testObjects | object ...testObject - Selector or TheoreticalProperty objects or plain objects to be casted as TheoreticalProperty objects (can be passed as a single array of objects or as multiple object arguments)

Returns

array original passed objects in proper cascade order (does not mutate or return the original array if passed)

Throws

  • TheoreticalProperty objects may throw errors if invalid values are passed. See its documentation for more details.
escape()

Escape a JS value to use as a CSS identity. This is an implementation of the CSS spec which defines the CSS.escape() method, available in many browsers.

Params

  • mixed ident - raw value (will be casted as a string) to use as a CSS identity

Returns

string escaped identity that can be safely used to compose a CSS selector string

escapeString()

Escape a JS value to use as a CSS string. While escape() can be used for this purpose as well, it escapes more characters than necessary. This method only acts upon characters that must be escaped for use as a string, and returns the value with surronding double quotes.

Params

  • mixed string - raw value (will be casted as a string) to use as a CSS string

Returns

string escaped string, including surrounding double quote characters, that can be safely used to compose a CSS selector string

Selector

The Selector object is returned as the result of parsing a selector string, which gives access to the token data and specificity level. Selector objects must be instantiated with a token array, so such objects typically result from calling parse() rather than direct instantiation.

Constructor

  • array tokens - token objects

Properties

specificity

object contains properties a, b, c, and d, each with a count of the corresponding selectors of each specificity type

tokens

array array of token objects that comprise the compound selector, including combinators

Combinator Token Types

All combinator token objects have the following properties:

  • string type - the type of token
  • int location - the index in the original string where the token was located
  • string raw - the raw string that was parsed into the token

| Type | Example | Additional Properties | | - | - | - | | adjacentSiblingCombinator | sibling + nextsibling | null specificityType | | childCombinator | parent > child | null specificityType | | descendantCombinator | ancestor descendant | null specificityType | | generalSiblingCombinator | sibling ~ sibling | null specificityType |

Simple Selector Token Types

All simple selector token objects have the following properties:

  • string type - the type of token
  • int location - the index in the original string where the token was located
  • string raw - the raw string that was parsed into the token

| Type | Example | Additional Properties | | - | - | - | | attributePresenceSelector | [attr] | string name - attribute namestring | object | null namespace - namespace string, if provided; object with type: 'wildcard' if namespace is *; null if no namespacestring specificityType - c | | attributeValueSelector | [attr="value"] | string name - attribute namestring value - attribute valuestring operator - value comparison operator, one of: =, ~=, \|=, ^=, $=, *=string | object | null namespace - namespace string, if provided; object with type: 'wildcard' if namespace is *; null if no namespacestring specificityType - c | | classSelector | .class | string name - class namestring specificityType - c | | idSelector | #id | string name - IDstring specificityType - b | | negationSelector | :not(.class) | array tokens - simple selector token objectsnull specificityType | | pseudoClassSelector | :pseudo-class(expression) | string name - pseudo element nameobject | null expression - optional parenthetical expression as a data token objectstring specificityType - c | | pseudoElementSelector | ::pseudo-element | string name - pseudo element namestring specificityType - d | | typeSelector | element | string name - element namestring | object | null namespace - namespace string, if provided; object with type: 'wildcard' if namespace is *; null if no namespacestring specificityType - d | | universalSelector | * | string | object | null namespace - namespace string, if provided; object with type: 'wildcard' if namespace is *; null if no namespacenull specificityType |

Data Token Types

All data token objects have the following properties:

  • string type - the type of token
  • string raw - the raw string that was parsed into the token

| Type | Example | Additional Properties | | - | - | - | | identity | identity | string parsed - identity name | | nthFormula | 3n+4 | object parsed - object with properties a and b with their respective integer values from the an+b formula | | nthKeyword | even | string parsed - even or odd | | string | "string" | string parsed - value of string |

Methods

toString()

Returns

string properly formed selector string

TheoreticalProperty

TheoreticalProperty objects are used primarily to compare and sort different selectors. They are "theoretical" properties because they are not concerned with any property name or value, but rather the source of the property (e.g. user or author stylesheet or inline) and whether the !important directive is set, all which contribute to determining the cascading order of precedence of defined properties for an element.

The easiest way to use these objects is to not use them at all! Instead, you can pass Selector objects or plain objects to CSI.sort() and the TheoreticalProperty objects will be created under the hood for the comparison. However, it is more efficient to create and reuse TheoreticalProperty objects when doing multiple/repeated comparisons.

Constructor

  • object options | Selector selector | undefined - the constructor accepts a plain object which sets corresponding properties on the TheoreticalProperty object; as a shortcut, a Selector object may be passed instead, setting the selector property to that object and the origin property to "author"; if no argument is passed, the default properties are used, which make the object a non-important inline style

Properties

important

bool whether the property was defined with the !important directive (properties originating from a userAgent should not ever be important and will throw an error if used in a comparison)

Default: false

origin

string where the CSS property originates from, one of: user (configured in the user's browser settings), userAgent (defined by the browser itself), author (defined in an external stylesheet or <style> block), or inline (defined in an element's style="" attribute)

Default: "inline"

selector

Selector | null for CSS properties not originating from an inline style attribute, this should be set to a Selector object, otherwise this should be null (if the expected value does not match the defined origin, an error will be thrown upon comparison)

Default: null

Methods

getSpecificity()

Get the specificity of the selector/property. If the property's origin is a selector, the specificity object comes directly from the Selector object, otherwise it is always {a: 1, b: 0, c: 0, d: 0} for inline styles.

Returns

object plain object with properties a, b, c, d, based on how specificity is tallied

Throws

  • An error is thrown if the origin is invalid or does not match the expected value of selector
getPrecedenceLevel()

Based on the origin of the property and whether it is !important, determine the precendence level. A lower value indicates a higher precedence.

Returns

int precedence value, lower being higher precedence

Throws

  • An error is thrown if the origin type is invalid.

Notes

  • This package uses a number methods introduced by ECMAScript 2015 which may not be available in all environments. You may need to use a polyfill for the following methods:
  • The parsing functionality is built upon nearley, a JS implementation of the Earley Parsing Algorithm. I was introduced to nearley and inspired to use it for the purposes of CSS selector parsing by scalpel.
  • After evaluating several CSS selector parsers, my goal was to produce one that could handle any valid selector string based on the spec. As such, please file an issue if you come across any valid selector strings that cannot be parsed!