86 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			86 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
"use strict";
 | 
						|
Object.defineProperty(exports, "__esModule", { value: true });
 | 
						|
var css_what_1 = require("css-what");
 | 
						|
var procedure_1 = require("./procedure");
 | 
						|
var attributes = {
 | 
						|
    exists: 10,
 | 
						|
    equals: 8,
 | 
						|
    not: 7,
 | 
						|
    start: 6,
 | 
						|
    end: 6,
 | 
						|
    any: 5,
 | 
						|
    hyphen: 4,
 | 
						|
    element: 4,
 | 
						|
};
 | 
						|
/**
 | 
						|
 * Sort the parts of the passed selector,
 | 
						|
 * as there is potential for optimization
 | 
						|
 * (some types of selectors are faster than others)
 | 
						|
 *
 | 
						|
 * @param arr Selector to sort
 | 
						|
 */
 | 
						|
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;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
exports.default = sortByProcedure;
 | 
						|
function getProcedure(token) {
 | 
						|
    var proc = procedure_1.procedure[token.type];
 | 
						|
    if (token.type === css_what_1.SelectorType.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 (token.type === css_what_1.SelectorType.Pseudo) {
 | 
						|
        if (!token.data) {
 | 
						|
            proc = 3;
 | 
						|
        }
 | 
						|
        else if (token.name === "has" || token.name === "contains") {
 | 
						|
            proc = 0; // Expensive in any case
 | 
						|
        }
 | 
						|
        else if (Array.isArray(token.data)) {
 | 
						|
            // "matches" and "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;
 | 
						|
}
 |