You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			144 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			JavaScript
		
	
			
		
		
	
	
			144 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			JavaScript
		
	
| import { attributeRules } from "./attributes.js";
 | |
| import { compilePseudoSelector } from "./pseudo-selectors/index.js";
 | |
| import { SelectorType } from "css-what";
 | |
| function getElementParent(node, adapter) {
 | |
|     const parent = adapter.getParent(node);
 | |
|     if (parent && adapter.isTag(parent)) {
 | |
|         return parent;
 | |
|     }
 | |
|     return null;
 | |
| }
 | |
| /*
 | |
|  * All available rules
 | |
|  */
 | |
| export function compileGeneralSelector(next, selector, options, context, compileToken) {
 | |
|     const { adapter, equals } = options;
 | |
|     switch (selector.type) {
 | |
|         case SelectorType.PseudoElement: {
 | |
|             throw new Error("Pseudo-elements are not supported by css-select");
 | |
|         }
 | |
|         case SelectorType.ColumnCombinator: {
 | |
|             throw new Error("Column combinators are not yet supported by css-select");
 | |
|         }
 | |
|         case SelectorType.Attribute: {
 | |
|             if (selector.namespace != null) {
 | |
|                 throw new Error("Namespaced attributes are not yet supported by css-select");
 | |
|             }
 | |
|             if (!options.xmlMode || options.lowerCaseAttributeNames) {
 | |
|                 selector.name = selector.name.toLowerCase();
 | |
|             }
 | |
|             return attributeRules[selector.action](next, selector, options);
 | |
|         }
 | |
|         case SelectorType.Pseudo: {
 | |
|             return compilePseudoSelector(next, selector, options, context, compileToken);
 | |
|         }
 | |
|         // Tags
 | |
|         case SelectorType.Tag: {
 | |
|             if (selector.namespace != null) {
 | |
|                 throw new Error("Namespaced tag names are not yet supported by css-select");
 | |
|             }
 | |
|             let { name } = selector;
 | |
|             if (!options.xmlMode || options.lowerCaseTags) {
 | |
|                 name = name.toLowerCase();
 | |
|             }
 | |
|             return function tag(elem) {
 | |
|                 return adapter.getName(elem) === name && next(elem);
 | |
|             };
 | |
|         }
 | |
|         // Traversal
 | |
|         case SelectorType.Descendant: {
 | |
|             if (options.cacheResults === false ||
 | |
|                 typeof WeakSet === "undefined") {
 | |
|                 return function descendant(elem) {
 | |
|                     let current = elem;
 | |
|                     while ((current = getElementParent(current, adapter))) {
 | |
|                         if (next(current)) {
 | |
|                             return true;
 | |
|                         }
 | |
|                     }
 | |
|                     return false;
 | |
|                 };
 | |
|             }
 | |
|             // @ts-expect-error `ElementNode` is not extending object
 | |
|             const isFalseCache = new WeakSet();
 | |
|             return function cachedDescendant(elem) {
 | |
|                 let current = elem;
 | |
|                 while ((current = getElementParent(current, adapter))) {
 | |
|                     if (!isFalseCache.has(current)) {
 | |
|                         if (adapter.isTag(current) && next(current)) {
 | |
|                             return true;
 | |
|                         }
 | |
|                         isFalseCache.add(current);
 | |
|                     }
 | |
|                 }
 | |
|                 return false;
 | |
|             };
 | |
|         }
 | |
|         case "_flexibleDescendant": {
 | |
|             // Include element itself, only used while querying an array
 | |
|             return function flexibleDescendant(elem) {
 | |
|                 let current = elem;
 | |
|                 do {
 | |
|                     if (next(current))
 | |
|                         return true;
 | |
|                 } while ((current = getElementParent(current, adapter)));
 | |
|                 return false;
 | |
|             };
 | |
|         }
 | |
|         case SelectorType.Parent: {
 | |
|             return function parent(elem) {
 | |
|                 return adapter
 | |
|                     .getChildren(elem)
 | |
|                     .some((elem) => adapter.isTag(elem) && next(elem));
 | |
|             };
 | |
|         }
 | |
|         case SelectorType.Child: {
 | |
|             return function child(elem) {
 | |
|                 const parent = adapter.getParent(elem);
 | |
|                 return parent != null && adapter.isTag(parent) && next(parent);
 | |
|             };
 | |
|         }
 | |
|         case SelectorType.Sibling: {
 | |
|             return function sibling(elem) {
 | |
|                 const siblings = adapter.getSiblings(elem);
 | |
|                 for (let i = 0; i < siblings.length; i++) {
 | |
|                     const currentSibling = siblings[i];
 | |
|                     if (equals(elem, currentSibling))
 | |
|                         break;
 | |
|                     if (adapter.isTag(currentSibling) && next(currentSibling)) {
 | |
|                         return true;
 | |
|                     }
 | |
|                 }
 | |
|                 return false;
 | |
|             };
 | |
|         }
 | |
|         case SelectorType.Adjacent: {
 | |
|             if (adapter.prevElementSibling) {
 | |
|                 return function adjacent(elem) {
 | |
|                     const previous = adapter.prevElementSibling(elem);
 | |
|                     return previous != null && next(previous);
 | |
|                 };
 | |
|             }
 | |
|             return function adjacent(elem) {
 | |
|                 const siblings = adapter.getSiblings(elem);
 | |
|                 let lastElement;
 | |
|                 for (let i = 0; i < siblings.length; i++) {
 | |
|                     const currentSibling = siblings[i];
 | |
|                     if (equals(elem, currentSibling))
 | |
|                         break;
 | |
|                     if (adapter.isTag(currentSibling)) {
 | |
|                         lastElement = currentSibling;
 | |
|                     }
 | |
|                 }
 | |
|                 return !!lastElement && next(lastElement);
 | |
|             };
 | |
|         }
 | |
|         case SelectorType.Universal: {
 | |
|             if (selector.namespace != null && selector.namespace !== "*") {
 | |
|                 throw new Error("Namespaced universal selectors are not yet supported by css-select");
 | |
|             }
 | |
|             return next;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| //# sourceMappingURL=general.js.map
 |