sort.js 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. import { AttributeAction, SelectorType } from "css-what";
  2. const procedure = new Map([
  3. [SelectorType.Universal, 50],
  4. [SelectorType.Tag, 30],
  5. [SelectorType.Attribute, 1],
  6. [SelectorType.Pseudo, 0],
  7. ]);
  8. export function isTraversal(token) {
  9. return !procedure.has(token.type);
  10. }
  11. const attributes = new Map([
  12. [AttributeAction.Exists, 10],
  13. [AttributeAction.Equals, 8],
  14. [AttributeAction.Not, 7],
  15. [AttributeAction.Start, 6],
  16. [AttributeAction.End, 6],
  17. [AttributeAction.Any, 5],
  18. ]);
  19. /**
  20. * Sort the parts of the passed selector,
  21. * as there is potential for optimization
  22. * (some types of selectors are faster than others)
  23. *
  24. * @param arr Selector to sort
  25. */
  26. export default function sortByProcedure(arr) {
  27. const procs = arr.map(getProcedure);
  28. for (let i = 1; i < arr.length; i++) {
  29. const procNew = procs[i];
  30. if (procNew < 0)
  31. continue;
  32. for (let j = i - 1; j >= 0 && procNew < procs[j]; j--) {
  33. const token = arr[j + 1];
  34. arr[j + 1] = arr[j];
  35. arr[j] = token;
  36. procs[j + 1] = procs[j];
  37. procs[j] = procNew;
  38. }
  39. }
  40. }
  41. function getProcedure(token) {
  42. var _a, _b;
  43. let proc = (_a = procedure.get(token.type)) !== null && _a !== void 0 ? _a : -1;
  44. if (token.type === SelectorType.Attribute) {
  45. proc = (_b = attributes.get(token.action)) !== null && _b !== void 0 ? _b : 4;
  46. if (token.action === AttributeAction.Equals && token.name === "id") {
  47. // Prefer ID selectors (eg. #ID)
  48. proc = 9;
  49. }
  50. if (token.ignoreCase) {
  51. /*
  52. * IgnoreCase adds some overhead, prefer "normal" token
  53. * this is a binary operation, to ensure it's still an int
  54. */
  55. proc >>= 1;
  56. }
  57. }
  58. else if (token.type === SelectorType.Pseudo) {
  59. if (!token.data) {
  60. proc = 3;
  61. }
  62. else if (token.name === "has" || token.name === "contains") {
  63. proc = 0; // Expensive in any case
  64. }
  65. else if (Array.isArray(token.data)) {
  66. // Eg. :matches, :not
  67. proc = Math.min(...token.data.map((d) => Math.min(...d.map(getProcedure))));
  68. // If we have traversals, try to avoid executing this selector
  69. if (proc < 0) {
  70. proc = 0;
  71. }
  72. }
  73. else {
  74. proc = 2;
  75. }
  76. }
  77. return proc;
  78. }
  79. //# sourceMappingURL=sort.js.map