You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

80 lines
2.1 KiB

4 years ago
  1. module.exports = sortByProcedure;
  2. /*
  3. sort the parts of the passed selector,
  4. as there is potential for optimization
  5. (some types of selectors are faster than others)
  6. */
  7. var procedure = require("./procedure.json");
  8. var attributes = {
  9. __proto__: null,
  10. exists: 10,
  11. equals: 8,
  12. not: 7,
  13. start: 6,
  14. end: 6,
  15. any: 5,
  16. hyphen: 4,
  17. element: 4
  18. };
  19. function sortByProcedure(arr) {
  20. var procs = arr.map(getProcedure);
  21. for (var i = 1; i < arr.length; i++) {
  22. var procNew = procs[i];
  23. if (procNew < 0) continue;
  24. for (var j = i - 1; j >= 0 && procNew < procs[j]; j--) {
  25. var token = arr[j + 1];
  26. arr[j + 1] = arr[j];
  27. arr[j] = token;
  28. procs[j + 1] = procs[j];
  29. procs[j] = procNew;
  30. }
  31. }
  32. }
  33. function getProcedure(token) {
  34. var proc = procedure[token.type];
  35. if (proc === procedure.attribute) {
  36. proc = attributes[token.action];
  37. if (proc === attributes.equals && token.name === "id") {
  38. //prefer ID selectors (eg. #ID)
  39. proc = 9;
  40. }
  41. if (token.ignoreCase) {
  42. //ignoreCase adds some overhead, prefer "normal" token
  43. //this is a binary operation, to ensure it's still an int
  44. proc >>= 1;
  45. }
  46. } else if (proc === procedure.pseudo) {
  47. if (!token.data) {
  48. proc = 3;
  49. } else if (token.name === "has" || token.name === "contains") {
  50. proc = 0; //expensive in any case
  51. } else if (token.name === "matches" || token.name === "not") {
  52. proc = 0;
  53. for (var i = 0; i < token.data.length; i++) {
  54. //TODO better handling of complex selectors
  55. if (token.data[i].length !== 1) continue;
  56. var cur = getProcedure(token.data[i][0]);
  57. //avoid executing :has or :contains
  58. if (cur === 0) {
  59. proc = 0;
  60. break;
  61. }
  62. if (cur > proc) proc = cur;
  63. }
  64. if (token.data.length > 1 && proc > 0) proc -= 1;
  65. } else {
  66. proc = 1;
  67. }
  68. }
  69. return proc;
  70. }