|
|
import { AttributeAction, SelectorType, isTraversal as isTraversalBase, } from "css-what"; |
|
|
export function isTraversal(token) { |
|
|
return token.type === "_flexibleDescendant" || isTraversalBase(token); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function sortRules(arr) { |
|
|
const ratings = arr.map(getQuality); |
|
|
for (let i = 1; i < arr.length; i++) { |
|
|
const procNew = ratings[i]; |
|
|
if (procNew < 0) |
|
|
continue; |
|
|
|
|
|
for (let j = i; j > 0 && procNew < ratings[j - 1]; j--) { |
|
|
const token = arr[j]; |
|
|
arr[j] = arr[j - 1]; |
|
|
arr[j - 1] = token; |
|
|
ratings[j] = ratings[j - 1]; |
|
|
ratings[j - 1] = procNew; |
|
|
} |
|
|
} |
|
|
} |
|
|
function getAttributeQuality(token) { |
|
|
switch (token.action) { |
|
|
case AttributeAction.Exists: { |
|
|
return 10; |
|
|
} |
|
|
case AttributeAction.Equals: { |
|
|
|
|
|
return token.name === "id" ? 9 : 8; |
|
|
} |
|
|
case AttributeAction.Not: { |
|
|
return 7; |
|
|
} |
|
|
case AttributeAction.Start: { |
|
|
return 6; |
|
|
} |
|
|
case AttributeAction.End: { |
|
|
return 6; |
|
|
} |
|
|
case AttributeAction.Any: { |
|
|
return 5; |
|
|
} |
|
|
case AttributeAction.Hyphen: { |
|
|
return 4; |
|
|
} |
|
|
case AttributeAction.Element: { |
|
|
return 3; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function getQuality(token) { |
|
|
|
|
|
switch (token.type) { |
|
|
case SelectorType.Universal: { |
|
|
return 50; |
|
|
} |
|
|
case SelectorType.Tag: { |
|
|
return 30; |
|
|
} |
|
|
case SelectorType.Attribute: { |
|
|
return Math.floor(getAttributeQuality(token) / |
|
|
|
|
|
(token.ignoreCase ? 2 : 1)); |
|
|
} |
|
|
case SelectorType.Pseudo: { |
|
|
return !token.data |
|
|
? 3 |
|
|
: token.name === "has" || |
|
|
token.name === "contains" || |
|
|
token.name === "icontains" |
|
|
? |
|
|
0 |
|
|
: Array.isArray(token.data) |
|
|
? |
|
|
Math.max( |
|
|
|
|
|
0, Math.min(...token.data.map((d) => Math.min(...d.map(getQuality))))) |
|
|
: 2; |
|
|
} |
|
|
default: { |
|
|
return -1; |
|
|
} |
|
|
} |
|
|
} |
|
|
export function includesScopePseudo(t) { |
|
|
return (t.type === SelectorType.Pseudo && |
|
|
(t.name === "scope" || |
|
|
(Array.isArray(t.data) && |
|
|
t.data.some((data) => data.some(includesScopePseudo))))); |
|
|
} |
|
|
|