File size: 3,760 Bytes
a8063bc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isTraversal = isTraversal;
exports.sortRules = sortRules;
exports.getQuality = getQuality;
exports.includesScopePseudo = includesScopePseudo;
var css_what_1 = require("css-what");
function isTraversal(token) {
    return token.type === "_flexibleDescendant" || (0, css_what_1.isTraversal)(token);
}
/**
 * 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 sortRules(arr) {
    var ratings = arr.map(getQuality);
    for (var i = 1; i < arr.length; i++) {
        var procNew = ratings[i];
        if (procNew < 0)
            continue;
        // Use insertion sort to move the token to the correct position.
        for (var j = i; j > 0 && procNew < ratings[j - 1]; j--) {
            var token = arr[j];
            arr[j] = arr[j - 1];
            arr[j - 1] = token;
            ratings[j] = ratings[j - 1];
            ratings[j - 1] = procNew;
        }
    }
}
function getAttributeQuality(token) {
    switch (token.action) {
        case css_what_1.AttributeAction.Exists: {
            return 10;
        }
        case css_what_1.AttributeAction.Equals: {
            // Prefer ID selectors (eg. #ID)
            return token.name === "id" ? 9 : 8;
        }
        case css_what_1.AttributeAction.Not: {
            return 7;
        }
        case css_what_1.AttributeAction.Start: {
            return 6;
        }
        case css_what_1.AttributeAction.End: {
            return 6;
        }
        case css_what_1.AttributeAction.Any: {
            return 5;
        }
        case css_what_1.AttributeAction.Hyphen: {
            return 4;
        }
        case css_what_1.AttributeAction.Element: {
            return 3;
        }
    }
}
/**
 * Determine the quality of the passed token. The higher the number, the
 * faster the token is to execute.
 *
 * @param token Token to get the quality of.
 * @returns The token's quality.
 */
function getQuality(token) {
    // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
    switch (token.type) {
        case css_what_1.SelectorType.Universal: {
            return 50;
        }
        case css_what_1.SelectorType.Tag: {
            return 30;
        }
        case css_what_1.SelectorType.Attribute: {
            return Math.floor(getAttributeQuality(token) /
                // `ignoreCase` adds some overhead, half the result if applicable.
                (token.ignoreCase ? 2 : 1));
        }
        case css_what_1.SelectorType.Pseudo: {
            return !token.data
                ? 3
                : token.name === "has" ||
                    token.name === "contains" ||
                    token.name === "icontains"
                    ? // Expensive in any case — run as late as possible.
                        0
                    : Array.isArray(token.data)
                        ? // Eg. `:is`, `:not`
                            Math.max(
                            // If we have traversals, try to avoid executing this selector
                            0, Math.min.apply(Math, token.data.map(function (d) {
                                return Math.min.apply(Math, d.map(getQuality));
                            })))
                        : 2;
        }
        default: {
            return -1;
        }
    }
}
function includesScopePseudo(t) {
    return (t.type === css_what_1.SelectorType.Pseudo &&
        (t.name === "scope" ||
            (Array.isArray(t.data) &&
                t.data.some(function (data) { return data.some(includesScopePseudo); }))));
}
//# sourceMappingURL=selectors.js.map