import { tokenize , RECURSIVE_PSEUDO_CLASSES } from './parse' ; export const EXTENDED_PSEUDO_CLASSES = new Set ( [ 'has' , 'has-text' , 'if' , ] ) ; export const PSEUDO_CLASSES = new Set ( [ 'active' , 'any' , 'any-link' , 'blank' , 'checked' , 'default' , 'defined' , 'dir' , 'disabled' , 'empty' , 'enabled' , 'first' , 'first-child' , 'first-of-type' , 'focus' , 'focus-visible' , 'focus-within' , 'fullscreen' , 'host' , 'host-context' , 'hover' , 'in-range' , 'indeterminate' , 'invalid' , 'is' , 'lang' , 'last-child' , 'last-of-type' , 'left' , 'link' , 'matches' , 'not' , 'nth-child' , 'nth-last-child' , 'nth-last-of-type' , 'nth-of-type' , 'only-child' , 'only-of-type' , 'optional' , 'out-of-range' , 'placeholder-shown' , 'read-only' , 'read-write' , 'required' , 'right' , 'root' , 'scope' , 'target' , 'valid' , 'visited' , 'where' , ] ) ; export const PSEUDO_ELEMENTS = new Set ( [ 'after' , 'before' , 'first-letter' , 'first-line' ] ) ; export enum SelectorType { Normal , Extended , Invalid } export function classifySelector ( selector ) { if ( selector . indexOf ( ':' ) === - 1 ) { return SelectorType . Normal ; } const tokens = tokenize ( selector ) ; let foundSupportedExtendedSelector = false ; for ( const token of tokens ) { if ( token . type === 'pseudo-class' ) { const { name } = token ; if ( EXTENDED_PSEUDO_CLASSES . has ( name ) === true ) { foundSupportedExtendedSelector = true ; } else if ( PSEUDO_CLASSES . has ( name ) === false && PSEUDO_ELEMENTS . has ( name ) === false ) { return SelectorType . Invalid ; } if ( foundSupportedExtendedSelector === false && token . argument !== undefined && RECURSIVE_PSEUDO_CLASSES . has ( name ) === true ) { const argumentType = classifySelector ( token . argument ) ; if ( argumentType === SelectorType . Invalid ) { return argumentType ; } else if ( argumentType === SelectorType . Extended ) { foundSupportedExtendedSelector = true ; } } } } if ( foundSupportedExtendedSelector === true ) { return SelectorType . Extended ; } return SelectorType . Normal ; }