|
|
- module.exports = sortByProcedure;
-
- /*
- sort the parts of the passed selector,
- as there is potential for optimization
- (some types of selectors are faster than others)
- */
-
- var procedure = require("./procedure.json");
-
- var attributes = {
- __proto__: null,
- exists: 10,
- equals: 8,
- not: 7,
- start: 6,
- end: 6,
- any: 5,
- hyphen: 4,
- element: 4
- };
-
- function sortByProcedure(arr) {
- var procs = arr.map(getProcedure);
- for (var i = 1; i < arr.length; i++) {
- var procNew = procs[i];
-
- if (procNew < 0) continue;
-
- for (var j = i - 1; j >= 0 && procNew < procs[j]; j--) {
- var token = arr[j + 1];
- arr[j + 1] = arr[j];
- arr[j] = token;
- procs[j + 1] = procs[j];
- procs[j] = procNew;
- }
- }
- }
-
- function getProcedure(token) {
- var proc = procedure[token.type];
-
- if (proc === procedure.attribute) {
- proc = attributes[token.action];
-
- if (proc === attributes.equals && token.name === "id") {
- //prefer ID selectors (eg. #ID)
- proc = 9;
- }
-
- if (token.ignoreCase) {
- //ignoreCase adds some overhead, prefer "normal" token
- //this is a binary operation, to ensure it's still an int
- proc >>= 1;
- }
- } else if (proc === procedure.pseudo) {
- if (!token.data) {
- proc = 3;
- } else if (token.name === "has" || token.name === "contains") {
- proc = 0; //expensive in any case
- } else if (token.name === "matches" || token.name === "not") {
- proc = 0;
- for (var i = 0; i < token.data.length; i++) {
- //TODO better handling of complex selectors
- if (token.data[i].length !== 1) continue;
- var cur = getProcedure(token.data[i][0]);
- //avoid executing :has or :contains
- if (cur === 0) {
- proc = 0;
- break;
- }
- if (cur > proc) proc = cur;
- }
- if (token.data.length > 1 && proc > 0) proc -= 1;
- } else {
- proc = 1;
- }
- }
- return proc;
- }
|