sort.js 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  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. }