@m2c2kit/build-helpers 0.3.26 → 0.3.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +691 -397
- package/package.json +6 -4
package/dist/index.js
CHANGED
|
@@ -3103,7 +3103,7 @@ function findOneChild(test, nodes) {
|
|
|
3103
3103
|
* @param recurse Also consider child nodes.
|
|
3104
3104
|
* @returns The first node that passes `test`.
|
|
3105
3105
|
*/
|
|
3106
|
-
function findOne(test, nodes, recurse = true) {
|
|
3106
|
+
function findOne$1(test, nodes, recurse = true) {
|
|
3107
3107
|
const searchedNodes = Array.isArray(nodes) ? nodes : [nodes];
|
|
3108
3108
|
for (let i = 0; i < searchedNodes.length; i++) {
|
|
3109
3109
|
const node = searchedNodes[i];
|
|
@@ -3111,7 +3111,9 @@ function findOne(test, nodes, recurse = true) {
|
|
|
3111
3111
|
return node;
|
|
3112
3112
|
}
|
|
3113
3113
|
if (recurse && hasChildren(node) && node.children.length > 0) {
|
|
3114
|
-
|
|
3114
|
+
const found = findOne$1(test, node.children, true);
|
|
3115
|
+
if (found)
|
|
3116
|
+
return found;
|
|
3115
3117
|
}
|
|
3116
3118
|
}
|
|
3117
3119
|
return null;
|
|
@@ -3138,7 +3140,7 @@ function existsOne(test, nodes) {
|
|
|
3138
3140
|
* @param nodes Array of nodes to search.
|
|
3139
3141
|
* @returns All nodes passing `test`.
|
|
3140
3142
|
*/
|
|
3141
|
-
function findAll(test, nodes) {
|
|
3143
|
+
function findAll$1(test, nodes) {
|
|
3142
3144
|
const result = [];
|
|
3143
3145
|
const nodeStack = [Array.isArray(nodes) ? nodes : [nodes]];
|
|
3144
3146
|
const indexStack = [0];
|
|
@@ -3271,7 +3273,7 @@ function getElements(options, nodes, recurse, limit = Infinity) {
|
|
|
3271
3273
|
function getElementById(id, nodes, recurse = true) {
|
|
3272
3274
|
if (!Array.isArray(nodes))
|
|
3273
3275
|
nodes = [nodes];
|
|
3274
|
-
return findOne(getAttribCheck("id", id), nodes, recurse);
|
|
3276
|
+
return findOne$1(getAttribCheck("id", id), nodes, recurse);
|
|
3275
3277
|
}
|
|
3276
3278
|
/**
|
|
3277
3279
|
* Returns all nodes with the supplied `tagName`.
|
|
@@ -3638,8 +3640,8 @@ var DomUtils = /*#__PURE__*/Object.freeze({
|
|
|
3638
3640
|
existsOne: existsOne,
|
|
3639
3641
|
filter: filter,
|
|
3640
3642
|
find: find,
|
|
3641
|
-
findAll: findAll,
|
|
3642
|
-
findOne: findOne,
|
|
3643
|
+
findAll: findAll$1,
|
|
3644
|
+
findOne: findOne$1,
|
|
3643
3645
|
findOneChild: findOneChild,
|
|
3644
3646
|
getAttributeValue: getAttributeValue,
|
|
3645
3647
|
getChildren: getChildren,
|
|
@@ -3741,15 +3743,49 @@ var AttributeAction;
|
|
|
3741
3743
|
AttributeAction["Start"] = "start";
|
|
3742
3744
|
})(AttributeAction || (AttributeAction = {}));
|
|
3743
3745
|
|
|
3744
|
-
const reName = /^[
|
|
3746
|
+
const reName = /^[^#\\]?(?:\\(?:[\da-f]{1,6}\s?|.)|[\w\u00B0-\uFFFF-])+/;
|
|
3745
3747
|
const reEscape = /\\([\da-f]{1,6}\s?|(\s)|.)/gi;
|
|
3748
|
+
var CharCode;
|
|
3749
|
+
(function (CharCode) {
|
|
3750
|
+
CharCode[CharCode["LeftParenthesis"] = 40] = "LeftParenthesis";
|
|
3751
|
+
CharCode[CharCode["RightParenthesis"] = 41] = "RightParenthesis";
|
|
3752
|
+
CharCode[CharCode["LeftSquareBracket"] = 91] = "LeftSquareBracket";
|
|
3753
|
+
CharCode[CharCode["RightSquareBracket"] = 93] = "RightSquareBracket";
|
|
3754
|
+
CharCode[CharCode["Comma"] = 44] = "Comma";
|
|
3755
|
+
CharCode[CharCode["Period"] = 46] = "Period";
|
|
3756
|
+
CharCode[CharCode["Colon"] = 58] = "Colon";
|
|
3757
|
+
CharCode[CharCode["SingleQuote"] = 39] = "SingleQuote";
|
|
3758
|
+
CharCode[CharCode["DoubleQuote"] = 34] = "DoubleQuote";
|
|
3759
|
+
CharCode[CharCode["Plus"] = 43] = "Plus";
|
|
3760
|
+
CharCode[CharCode["Tilde"] = 126] = "Tilde";
|
|
3761
|
+
CharCode[CharCode["QuestionMark"] = 63] = "QuestionMark";
|
|
3762
|
+
CharCode[CharCode["ExclamationMark"] = 33] = "ExclamationMark";
|
|
3763
|
+
CharCode[CharCode["Slash"] = 47] = "Slash";
|
|
3764
|
+
CharCode[CharCode["Equal"] = 61] = "Equal";
|
|
3765
|
+
CharCode[CharCode["Dollar"] = 36] = "Dollar";
|
|
3766
|
+
CharCode[CharCode["Pipe"] = 124] = "Pipe";
|
|
3767
|
+
CharCode[CharCode["Circumflex"] = 94] = "Circumflex";
|
|
3768
|
+
CharCode[CharCode["Asterisk"] = 42] = "Asterisk";
|
|
3769
|
+
CharCode[CharCode["GreaterThan"] = 62] = "GreaterThan";
|
|
3770
|
+
CharCode[CharCode["LessThan"] = 60] = "LessThan";
|
|
3771
|
+
CharCode[CharCode["Hash"] = 35] = "Hash";
|
|
3772
|
+
CharCode[CharCode["LowerI"] = 105] = "LowerI";
|
|
3773
|
+
CharCode[CharCode["LowerS"] = 115] = "LowerS";
|
|
3774
|
+
CharCode[CharCode["BackSlash"] = 92] = "BackSlash";
|
|
3775
|
+
// Whitespace
|
|
3776
|
+
CharCode[CharCode["Space"] = 32] = "Space";
|
|
3777
|
+
CharCode[CharCode["Tab"] = 9] = "Tab";
|
|
3778
|
+
CharCode[CharCode["NewLine"] = 10] = "NewLine";
|
|
3779
|
+
CharCode[CharCode["FormFeed"] = 12] = "FormFeed";
|
|
3780
|
+
CharCode[CharCode["CarriageReturn"] = 13] = "CarriageReturn";
|
|
3781
|
+
})(CharCode || (CharCode = {}));
|
|
3746
3782
|
const actionTypes = new Map([
|
|
3747
|
-
[
|
|
3748
|
-
[
|
|
3749
|
-
[
|
|
3750
|
-
[
|
|
3751
|
-
[
|
|
3752
|
-
[
|
|
3783
|
+
[CharCode.Tilde, AttributeAction.Element],
|
|
3784
|
+
[CharCode.Circumflex, AttributeAction.Start],
|
|
3785
|
+
[CharCode.Dollar, AttributeAction.End],
|
|
3786
|
+
[CharCode.Asterisk, AttributeAction.Any],
|
|
3787
|
+
[CharCode.ExclamationMark, AttributeAction.Not],
|
|
3788
|
+
[CharCode.Pipe, AttributeAction.Hyphen],
|
|
3753
3789
|
]);
|
|
3754
3790
|
// Pseudos, whose data property is parsed as well.
|
|
3755
3791
|
const unpackPseudos = new Set([
|
|
@@ -3761,6 +3797,18 @@ const unpackPseudos = new Set([
|
|
|
3761
3797
|
"host",
|
|
3762
3798
|
"host-context",
|
|
3763
3799
|
]);
|
|
3800
|
+
/**
|
|
3801
|
+
* Pseudo elements defined in CSS Level 1 and CSS Level 2 can be written with
|
|
3802
|
+
* a single colon; eg. :before will turn into ::before.
|
|
3803
|
+
*
|
|
3804
|
+
* @see {@link https://www.w3.org/TR/2018/WD-selectors-4-20181121/#pseudo-element-syntax}
|
|
3805
|
+
*/
|
|
3806
|
+
const pseudosToPseudoElements = new Set([
|
|
3807
|
+
"before",
|
|
3808
|
+
"after",
|
|
3809
|
+
"first-line",
|
|
3810
|
+
"first-letter",
|
|
3811
|
+
]);
|
|
3764
3812
|
/**
|
|
3765
3813
|
* Checks whether a specific selector is a traversal.
|
|
3766
3814
|
* This is useful eg. in swapping the order of elements that
|
|
@@ -3775,43 +3823,44 @@ function isTraversal$1(selector) {
|
|
|
3775
3823
|
case SelectorType.Descendant:
|
|
3776
3824
|
case SelectorType.Parent:
|
|
3777
3825
|
case SelectorType.Sibling:
|
|
3778
|
-
case SelectorType.ColumnCombinator:
|
|
3826
|
+
case SelectorType.ColumnCombinator: {
|
|
3779
3827
|
return true;
|
|
3780
|
-
|
|
3828
|
+
}
|
|
3829
|
+
default: {
|
|
3781
3830
|
return false;
|
|
3831
|
+
}
|
|
3782
3832
|
}
|
|
3783
3833
|
}
|
|
3784
3834
|
const stripQuotesFromPseudos = new Set(["contains", "icontains"]);
|
|
3785
3835
|
// Unescape function taken from https://github.com/jquery/sizzle/blob/master/src/sizzle.js#L152
|
|
3786
3836
|
function funescape(_, escaped, escapedWhitespace) {
|
|
3787
|
-
const high = parseInt(escaped, 16) -
|
|
3837
|
+
const high = Number.parseInt(escaped, 16) - 65536;
|
|
3788
3838
|
// NaN means non-codepoint
|
|
3789
3839
|
return high !== high || escapedWhitespace
|
|
3790
3840
|
? escaped
|
|
3791
3841
|
: high < 0
|
|
3792
3842
|
? // BMP codepoint
|
|
3793
|
-
String.fromCharCode(high +
|
|
3843
|
+
String.fromCharCode(high + 65536)
|
|
3794
3844
|
: // Supplemental Plane codepoint (surrogate pair)
|
|
3795
|
-
String.fromCharCode((high >> 10) |
|
|
3845
|
+
String.fromCharCode((high >> 10) | 55296, (high & 1023) | 56320);
|
|
3796
3846
|
}
|
|
3797
|
-
function unescapeCSS(
|
|
3798
|
-
return
|
|
3847
|
+
function unescapeCSS(cssString) {
|
|
3848
|
+
return cssString.replace(reEscape, funescape);
|
|
3799
3849
|
}
|
|
3800
3850
|
function isQuote(c) {
|
|
3801
|
-
return c ===
|
|
3851
|
+
return c === CharCode.SingleQuote || c === CharCode.DoubleQuote;
|
|
3802
3852
|
}
|
|
3803
3853
|
function isWhitespace(c) {
|
|
3804
|
-
return (c ===
|
|
3805
|
-
c ===
|
|
3806
|
-
c ===
|
|
3807
|
-
c ===
|
|
3808
|
-
c ===
|
|
3854
|
+
return (c === CharCode.Space ||
|
|
3855
|
+
c === CharCode.Tab ||
|
|
3856
|
+
c === CharCode.NewLine ||
|
|
3857
|
+
c === CharCode.FormFeed ||
|
|
3858
|
+
c === CharCode.CarriageReturn);
|
|
3809
3859
|
}
|
|
3810
3860
|
/**
|
|
3811
|
-
* Parses `selector
|
|
3861
|
+
* Parses `selector`.
|
|
3812
3862
|
*
|
|
3813
3863
|
* @param selector Selector to parse.
|
|
3814
|
-
* @param options Options for parsing.
|
|
3815
3864
|
* @returns Returns a two-dimensional array.
|
|
3816
3865
|
* The first dimension represents selectors separated by commas (eg. `sub1, sub2`),
|
|
3817
3866
|
* the second contains the relevant tokens for that selector.
|
|
@@ -3845,29 +3894,27 @@ function parseSelector(subselects, selector, selectorIndex) {
|
|
|
3845
3894
|
function readValueWithParenthesis() {
|
|
3846
3895
|
selectorIndex += 1;
|
|
3847
3896
|
const start = selectorIndex;
|
|
3848
|
-
let counter = 1;
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3897
|
+
for (let counter = 1; selectorIndex < selector.length; selectorIndex++) {
|
|
3898
|
+
switch (selector.charCodeAt(selectorIndex)) {
|
|
3899
|
+
case CharCode.BackSlash: {
|
|
3900
|
+
// Skip next character
|
|
3901
|
+
selectorIndex += 1;
|
|
3902
|
+
break;
|
|
3903
|
+
}
|
|
3904
|
+
case CharCode.LeftParenthesis: {
|
|
3905
|
+
counter += 1;
|
|
3906
|
+
break;
|
|
3907
|
+
}
|
|
3908
|
+
case CharCode.RightParenthesis: {
|
|
3909
|
+
counter -= 1;
|
|
3910
|
+
if (counter === 0) {
|
|
3911
|
+
return unescapeCSS(selector.slice(start, selectorIndex++));
|
|
3912
|
+
}
|
|
3913
|
+
break;
|
|
3914
|
+
}
|
|
3859
3915
|
}
|
|
3860
3916
|
}
|
|
3861
|
-
|
|
3862
|
-
throw new Error("Parenthesis not matched");
|
|
3863
|
-
}
|
|
3864
|
-
return unescapeCSS(selector.slice(start, selectorIndex - 1));
|
|
3865
|
-
}
|
|
3866
|
-
function isEscaped(pos) {
|
|
3867
|
-
let slashCount = 0;
|
|
3868
|
-
while (selector.charCodeAt(--pos) === 92 /* BackSlash */)
|
|
3869
|
-
slashCount++;
|
|
3870
|
-
return (slashCount & 1) === 1;
|
|
3917
|
+
throw new Error("Parenthesis not matched");
|
|
3871
3918
|
}
|
|
3872
3919
|
function ensureNotTraversal() {
|
|
3873
3920
|
if (tokens.length > 0 && isTraversal$1(tokens[tokens.length - 1])) {
|
|
@@ -3901,7 +3948,7 @@ function parseSelector(subselects, selector, selectorIndex) {
|
|
|
3901
3948
|
* picked up from here.
|
|
3902
3949
|
*/
|
|
3903
3950
|
function finalizeSubselector() {
|
|
3904
|
-
if (tokens.length &&
|
|
3951
|
+
if (tokens.length > 0 &&
|
|
3905
3952
|
tokens[tokens.length - 1].type === SelectorType.Descendant) {
|
|
3906
3953
|
tokens.pop();
|
|
3907
3954
|
}
|
|
@@ -3918,11 +3965,11 @@ function parseSelector(subselects, selector, selectorIndex) {
|
|
|
3918
3965
|
const firstChar = selector.charCodeAt(selectorIndex);
|
|
3919
3966
|
switch (firstChar) {
|
|
3920
3967
|
// Whitespace
|
|
3921
|
-
case
|
|
3922
|
-
case
|
|
3923
|
-
case
|
|
3924
|
-
case
|
|
3925
|
-
case
|
|
3968
|
+
case CharCode.Space:
|
|
3969
|
+
case CharCode.Tab:
|
|
3970
|
+
case CharCode.NewLine:
|
|
3971
|
+
case CharCode.FormFeed:
|
|
3972
|
+
case CharCode.CarriageReturn: {
|
|
3926
3973
|
if (tokens.length === 0 ||
|
|
3927
3974
|
tokens[0].type !== SelectorType.Descendant) {
|
|
3928
3975
|
ensureNotTraversal();
|
|
@@ -3932,41 +3979,41 @@ function parseSelector(subselects, selector, selectorIndex) {
|
|
|
3932
3979
|
break;
|
|
3933
3980
|
}
|
|
3934
3981
|
// Traversals
|
|
3935
|
-
case
|
|
3982
|
+
case CharCode.GreaterThan: {
|
|
3936
3983
|
addTraversal(SelectorType.Child);
|
|
3937
3984
|
stripWhitespace(1);
|
|
3938
3985
|
break;
|
|
3939
3986
|
}
|
|
3940
|
-
case
|
|
3987
|
+
case CharCode.LessThan: {
|
|
3941
3988
|
addTraversal(SelectorType.Parent);
|
|
3942
3989
|
stripWhitespace(1);
|
|
3943
3990
|
break;
|
|
3944
3991
|
}
|
|
3945
|
-
case
|
|
3992
|
+
case CharCode.Tilde: {
|
|
3946
3993
|
addTraversal(SelectorType.Sibling);
|
|
3947
3994
|
stripWhitespace(1);
|
|
3948
3995
|
break;
|
|
3949
3996
|
}
|
|
3950
|
-
case
|
|
3997
|
+
case CharCode.Plus: {
|
|
3951
3998
|
addTraversal(SelectorType.Adjacent);
|
|
3952
3999
|
stripWhitespace(1);
|
|
3953
4000
|
break;
|
|
3954
4001
|
}
|
|
3955
4002
|
// Special attribute selectors: .class, #id
|
|
3956
|
-
case
|
|
4003
|
+
case CharCode.Period: {
|
|
3957
4004
|
addSpecialAttribute("class", AttributeAction.Element);
|
|
3958
4005
|
break;
|
|
3959
4006
|
}
|
|
3960
|
-
case
|
|
4007
|
+
case CharCode.Hash: {
|
|
3961
4008
|
addSpecialAttribute("id", AttributeAction.Equals);
|
|
3962
4009
|
break;
|
|
3963
4010
|
}
|
|
3964
|
-
case
|
|
4011
|
+
case CharCode.LeftSquareBracket: {
|
|
3965
4012
|
stripWhitespace(1);
|
|
3966
4013
|
// Determine attribute name and namespace
|
|
3967
4014
|
let name;
|
|
3968
4015
|
let namespace = null;
|
|
3969
|
-
if (selector.charCodeAt(selectorIndex) ===
|
|
4016
|
+
if (selector.charCodeAt(selectorIndex) === CharCode.Pipe) {
|
|
3970
4017
|
// Equivalent to no namespace
|
|
3971
4018
|
name = getName(1);
|
|
3972
4019
|
}
|
|
@@ -3976,9 +4023,9 @@ function parseSelector(subselects, selector, selectorIndex) {
|
|
|
3976
4023
|
}
|
|
3977
4024
|
else {
|
|
3978
4025
|
name = getName(0);
|
|
3979
|
-
if (selector.charCodeAt(selectorIndex) ===
|
|
4026
|
+
if (selector.charCodeAt(selectorIndex) === CharCode.Pipe &&
|
|
3980
4027
|
selector.charCodeAt(selectorIndex + 1) !==
|
|
3981
|
-
|
|
4028
|
+
CharCode.Equal) {
|
|
3982
4029
|
namespace = name;
|
|
3983
4030
|
name = getName(1);
|
|
3984
4031
|
}
|
|
@@ -3990,12 +4037,12 @@ function parseSelector(subselects, selector, selectorIndex) {
|
|
|
3990
4037
|
if (possibleAction) {
|
|
3991
4038
|
action = possibleAction;
|
|
3992
4039
|
if (selector.charCodeAt(selectorIndex + 1) !==
|
|
3993
|
-
|
|
4040
|
+
CharCode.Equal) {
|
|
3994
4041
|
throw new Error("Expected `=`");
|
|
3995
4042
|
}
|
|
3996
4043
|
stripWhitespace(2);
|
|
3997
4044
|
}
|
|
3998
|
-
else if (selector.charCodeAt(selectorIndex) ===
|
|
4045
|
+
else if (selector.charCodeAt(selectorIndex) === CharCode.Equal) {
|
|
3999
4046
|
action = AttributeAction.Equals;
|
|
4000
4047
|
stripWhitespace(1);
|
|
4001
4048
|
}
|
|
@@ -4005,44 +4052,56 @@ function parseSelector(subselects, selector, selectorIndex) {
|
|
|
4005
4052
|
if (action !== "exists") {
|
|
4006
4053
|
if (isQuote(selector.charCodeAt(selectorIndex))) {
|
|
4007
4054
|
const quote = selector.charCodeAt(selectorIndex);
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4055
|
+
selectorIndex += 1;
|
|
4056
|
+
const sectionStart = selectorIndex;
|
|
4057
|
+
while (selectorIndex < selector.length &&
|
|
4058
|
+
selector.charCodeAt(selectorIndex) !== quote) {
|
|
4059
|
+
selectorIndex +=
|
|
4060
|
+
// Skip next character if it is escaped
|
|
4061
|
+
selector.charCodeAt(selectorIndex) ===
|
|
4062
|
+
CharCode.BackSlash
|
|
4063
|
+
? 2
|
|
4064
|
+
: 1;
|
|
4013
4065
|
}
|
|
4014
|
-
if (selector.charCodeAt(
|
|
4066
|
+
if (selector.charCodeAt(selectorIndex) !== quote) {
|
|
4015
4067
|
throw new Error("Attribute value didn't end");
|
|
4016
4068
|
}
|
|
4017
|
-
value = unescapeCSS(selector.slice(
|
|
4018
|
-
selectorIndex
|
|
4069
|
+
value = unescapeCSS(selector.slice(sectionStart, selectorIndex));
|
|
4070
|
+
selectorIndex += 1;
|
|
4019
4071
|
}
|
|
4020
4072
|
else {
|
|
4021
4073
|
const valueStart = selectorIndex;
|
|
4022
4074
|
while (selectorIndex < selector.length &&
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4075
|
+
!isWhitespace(selector.charCodeAt(selectorIndex)) &&
|
|
4076
|
+
selector.charCodeAt(selectorIndex) !==
|
|
4077
|
+
CharCode.RightSquareBracket) {
|
|
4078
|
+
selectorIndex +=
|
|
4079
|
+
// Skip next character if it is escaped
|
|
4080
|
+
selector.charCodeAt(selectorIndex) ===
|
|
4081
|
+
CharCode.BackSlash
|
|
4082
|
+
? 2
|
|
4083
|
+
: 1;
|
|
4028
4084
|
}
|
|
4029
4085
|
value = unescapeCSS(selector.slice(valueStart, selectorIndex));
|
|
4030
4086
|
}
|
|
4031
4087
|
stripWhitespace(0);
|
|
4032
4088
|
// See if we have a force ignore flag
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4089
|
+
switch (selector.charCodeAt(selectorIndex) | 0x20) {
|
|
4090
|
+
// If the forceIgnore flag is set (either `i` or `s`), use that value
|
|
4091
|
+
case CharCode.LowerI: {
|
|
4092
|
+
ignoreCase = true;
|
|
4093
|
+
stripWhitespace(1);
|
|
4094
|
+
break;
|
|
4095
|
+
}
|
|
4096
|
+
case CharCode.LowerS: {
|
|
4097
|
+
ignoreCase = false;
|
|
4098
|
+
stripWhitespace(1);
|
|
4099
|
+
break;
|
|
4100
|
+
}
|
|
4042
4101
|
}
|
|
4043
4102
|
}
|
|
4044
4103
|
if (selector.charCodeAt(selectorIndex) !==
|
|
4045
|
-
|
|
4104
|
+
CharCode.RightSquareBracket) {
|
|
4046
4105
|
throw new Error("Attribute selector didn't terminate");
|
|
4047
4106
|
}
|
|
4048
4107
|
selectorIndex += 1;
|
|
@@ -4057,22 +4116,30 @@ function parseSelector(subselects, selector, selectorIndex) {
|
|
|
4057
4116
|
tokens.push(attributeSelector);
|
|
4058
4117
|
break;
|
|
4059
4118
|
}
|
|
4060
|
-
case
|
|
4061
|
-
if (selector.charCodeAt(selectorIndex + 1) ===
|
|
4119
|
+
case CharCode.Colon: {
|
|
4120
|
+
if (selector.charCodeAt(selectorIndex + 1) === CharCode.Colon) {
|
|
4062
4121
|
tokens.push({
|
|
4063
4122
|
type: SelectorType.PseudoElement,
|
|
4064
4123
|
name: getName(2).toLowerCase(),
|
|
4065
4124
|
data: selector.charCodeAt(selectorIndex) ===
|
|
4066
|
-
|
|
4125
|
+
CharCode.LeftParenthesis
|
|
4067
4126
|
? readValueWithParenthesis()
|
|
4068
4127
|
: null,
|
|
4069
4128
|
});
|
|
4070
|
-
|
|
4129
|
+
break;
|
|
4071
4130
|
}
|
|
4072
4131
|
const name = getName(1).toLowerCase();
|
|
4132
|
+
if (pseudosToPseudoElements.has(name)) {
|
|
4133
|
+
tokens.push({
|
|
4134
|
+
type: SelectorType.PseudoElement,
|
|
4135
|
+
name,
|
|
4136
|
+
data: null,
|
|
4137
|
+
});
|
|
4138
|
+
break;
|
|
4139
|
+
}
|
|
4073
4140
|
let data = null;
|
|
4074
4141
|
if (selector.charCodeAt(selectorIndex) ===
|
|
4075
|
-
|
|
4142
|
+
CharCode.LeftParenthesis) {
|
|
4076
4143
|
if (unpackPseudos.has(name)) {
|
|
4077
4144
|
if (isQuote(selector.charCodeAt(selectorIndex + 1))) {
|
|
4078
4145
|
throw new Error(`Pseudo-selector ${name} cannot be quoted`);
|
|
@@ -4080,7 +4147,7 @@ function parseSelector(subselects, selector, selectorIndex) {
|
|
|
4080
4147
|
data = [];
|
|
4081
4148
|
selectorIndex = parseSelector(data, selector, selectorIndex + 1);
|
|
4082
4149
|
if (selector.charCodeAt(selectorIndex) !==
|
|
4083
|
-
|
|
4150
|
+
CharCode.RightParenthesis) {
|
|
4084
4151
|
throw new Error(`Missing closing parenthesis in :${name} (${selector})`);
|
|
4085
4152
|
}
|
|
4086
4153
|
selectorIndex += 1;
|
|
@@ -4100,7 +4167,7 @@ function parseSelector(subselects, selector, selectorIndex) {
|
|
|
4100
4167
|
tokens.push({ type: SelectorType.Pseudo, name, data });
|
|
4101
4168
|
break;
|
|
4102
4169
|
}
|
|
4103
|
-
case
|
|
4170
|
+
case CharCode.Comma: {
|
|
4104
4171
|
finalizeSubselector();
|
|
4105
4172
|
tokens = [];
|
|
4106
4173
|
stripWhitespace(1);
|
|
@@ -4121,13 +4188,13 @@ function parseSelector(subselects, selector, selectorIndex) {
|
|
|
4121
4188
|
}
|
|
4122
4189
|
let namespace = null;
|
|
4123
4190
|
let name;
|
|
4124
|
-
if (firstChar ===
|
|
4191
|
+
if (firstChar === CharCode.Asterisk) {
|
|
4125
4192
|
selectorIndex += 1;
|
|
4126
4193
|
name = "*";
|
|
4127
4194
|
}
|
|
4128
|
-
else if (firstChar ===
|
|
4195
|
+
else if (firstChar === CharCode.Pipe) {
|
|
4129
4196
|
name = "";
|
|
4130
|
-
if (selector.charCodeAt(selectorIndex + 1) ===
|
|
4197
|
+
if (selector.charCodeAt(selectorIndex + 1) === CharCode.Pipe) {
|
|
4131
4198
|
addTraversal(SelectorType.ColumnCombinator);
|
|
4132
4199
|
stripWhitespace(2);
|
|
4133
4200
|
break;
|
|
@@ -4139,11 +4206,11 @@ function parseSelector(subselects, selector, selectorIndex) {
|
|
|
4139
4206
|
else {
|
|
4140
4207
|
break loop;
|
|
4141
4208
|
}
|
|
4142
|
-
if (selector.charCodeAt(selectorIndex) ===
|
|
4143
|
-
selector.charCodeAt(selectorIndex + 1) !==
|
|
4209
|
+
if (selector.charCodeAt(selectorIndex) === CharCode.Pipe &&
|
|
4210
|
+
selector.charCodeAt(selectorIndex + 1) !== CharCode.Pipe) {
|
|
4144
4211
|
namespace = name;
|
|
4145
4212
|
if (selector.charCodeAt(selectorIndex + 1) ===
|
|
4146
|
-
|
|
4213
|
+
CharCode.Asterisk) {
|
|
4147
4214
|
name = "*";
|
|
4148
4215
|
selectorIndex += 2;
|
|
4149
4216
|
}
|
|
@@ -4161,84 +4228,6 @@ function parseSelector(subselects, selector, selectorIndex) {
|
|
|
4161
4228
|
return selectorIndex;
|
|
4162
4229
|
}
|
|
4163
4230
|
|
|
4164
|
-
const procedure = new Map([
|
|
4165
|
-
[SelectorType.Universal, 50],
|
|
4166
|
-
[SelectorType.Tag, 30],
|
|
4167
|
-
[SelectorType.Attribute, 1],
|
|
4168
|
-
[SelectorType.Pseudo, 0],
|
|
4169
|
-
]);
|
|
4170
|
-
function isTraversal(token) {
|
|
4171
|
-
return !procedure.has(token.type);
|
|
4172
|
-
}
|
|
4173
|
-
const attributes = new Map([
|
|
4174
|
-
[AttributeAction.Exists, 10],
|
|
4175
|
-
[AttributeAction.Equals, 8],
|
|
4176
|
-
[AttributeAction.Not, 7],
|
|
4177
|
-
[AttributeAction.Start, 6],
|
|
4178
|
-
[AttributeAction.End, 6],
|
|
4179
|
-
[AttributeAction.Any, 5],
|
|
4180
|
-
]);
|
|
4181
|
-
/**
|
|
4182
|
-
* Sort the parts of the passed selector,
|
|
4183
|
-
* as there is potential for optimization
|
|
4184
|
-
* (some types of selectors are faster than others)
|
|
4185
|
-
*
|
|
4186
|
-
* @param arr Selector to sort
|
|
4187
|
-
*/
|
|
4188
|
-
function sortByProcedure(arr) {
|
|
4189
|
-
const procs = arr.map(getProcedure);
|
|
4190
|
-
for (let i = 1; i < arr.length; i++) {
|
|
4191
|
-
const procNew = procs[i];
|
|
4192
|
-
if (procNew < 0)
|
|
4193
|
-
continue;
|
|
4194
|
-
for (let j = i - 1; j >= 0 && procNew < procs[j]; j--) {
|
|
4195
|
-
const token = arr[j + 1];
|
|
4196
|
-
arr[j + 1] = arr[j];
|
|
4197
|
-
arr[j] = token;
|
|
4198
|
-
procs[j + 1] = procs[j];
|
|
4199
|
-
procs[j] = procNew;
|
|
4200
|
-
}
|
|
4201
|
-
}
|
|
4202
|
-
}
|
|
4203
|
-
function getProcedure(token) {
|
|
4204
|
-
var _a, _b;
|
|
4205
|
-
let proc = (_a = procedure.get(token.type)) !== null && _a !== void 0 ? _a : -1;
|
|
4206
|
-
if (token.type === SelectorType.Attribute) {
|
|
4207
|
-
proc = (_b = attributes.get(token.action)) !== null && _b !== void 0 ? _b : 4;
|
|
4208
|
-
if (token.action === AttributeAction.Equals && token.name === "id") {
|
|
4209
|
-
// Prefer ID selectors (eg. #ID)
|
|
4210
|
-
proc = 9;
|
|
4211
|
-
}
|
|
4212
|
-
if (token.ignoreCase) {
|
|
4213
|
-
/*
|
|
4214
|
-
* IgnoreCase adds some overhead, prefer "normal" token
|
|
4215
|
-
* this is a binary operation, to ensure it's still an int
|
|
4216
|
-
*/
|
|
4217
|
-
proc >>= 1;
|
|
4218
|
-
}
|
|
4219
|
-
}
|
|
4220
|
-
else if (token.type === SelectorType.Pseudo) {
|
|
4221
|
-
if (!token.data) {
|
|
4222
|
-
proc = 3;
|
|
4223
|
-
}
|
|
4224
|
-
else if (token.name === "has" || token.name === "contains") {
|
|
4225
|
-
proc = 0; // Expensive in any case
|
|
4226
|
-
}
|
|
4227
|
-
else if (Array.isArray(token.data)) {
|
|
4228
|
-
// Eg. :matches, :not
|
|
4229
|
-
proc = Math.min(...token.data.map((d) => Math.min(...d.map(getProcedure))));
|
|
4230
|
-
// If we have traversals, try to avoid executing this selector
|
|
4231
|
-
if (proc < 0) {
|
|
4232
|
-
proc = 0;
|
|
4233
|
-
}
|
|
4234
|
-
}
|
|
4235
|
-
else {
|
|
4236
|
-
proc = 2;
|
|
4237
|
-
}
|
|
4238
|
-
}
|
|
4239
|
-
return proc;
|
|
4240
|
-
}
|
|
4241
|
-
|
|
4242
4231
|
/**
|
|
4243
4232
|
* All reserved characters in a regex, used for escaping.
|
|
4244
4233
|
*
|
|
@@ -4357,7 +4346,7 @@ const attributeRules = {
|
|
|
4357
4346
|
const { adapter } = options;
|
|
4358
4347
|
const { name, value } = data;
|
|
4359
4348
|
if (/\s/.test(value)) {
|
|
4360
|
-
return
|
|
4349
|
+
return boolbaseExports.falseFunc;
|
|
4361
4350
|
}
|
|
4362
4351
|
const regex = new RegExp(`(?:^|\\s)${escapeRegex(value)}(?:$|\\s)`, shouldIgnoreCase(data, options) ? "i" : "");
|
|
4363
4352
|
return function element(elem) {
|
|
@@ -4377,7 +4366,7 @@ const attributeRules = {
|
|
|
4377
4366
|
let { value } = data;
|
|
4378
4367
|
const len = value.length;
|
|
4379
4368
|
if (len === 0) {
|
|
4380
|
-
return
|
|
4369
|
+
return boolbaseExports.falseFunc;
|
|
4381
4370
|
}
|
|
4382
4371
|
if (shouldIgnoreCase(data, options)) {
|
|
4383
4372
|
value = value.toLowerCase();
|
|
@@ -4389,11 +4378,8 @@ const attributeRules = {
|
|
|
4389
4378
|
next(elem));
|
|
4390
4379
|
};
|
|
4391
4380
|
}
|
|
4392
|
-
return (elem) =>
|
|
4393
|
-
|
|
4394
|
-
return !!((_a = adapter.getAttributeValue(elem, name)) === null || _a === void 0 ? void 0 : _a.startsWith(value)) &&
|
|
4395
|
-
next(elem);
|
|
4396
|
-
};
|
|
4381
|
+
return (elem) => !!adapter.getAttributeValue(elem, name)?.startsWith(value) &&
|
|
4382
|
+
next(elem);
|
|
4397
4383
|
},
|
|
4398
4384
|
end(next, data, options) {
|
|
4399
4385
|
const { adapter } = options;
|
|
@@ -4401,27 +4387,23 @@ const attributeRules = {
|
|
|
4401
4387
|
let { value } = data;
|
|
4402
4388
|
const len = -value.length;
|
|
4403
4389
|
if (len === 0) {
|
|
4404
|
-
return
|
|
4390
|
+
return boolbaseExports.falseFunc;
|
|
4405
4391
|
}
|
|
4406
4392
|
if (shouldIgnoreCase(data, options)) {
|
|
4407
4393
|
value = value.toLowerCase();
|
|
4408
|
-
return (elem) =>
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
};
|
|
4394
|
+
return (elem) => adapter
|
|
4395
|
+
.getAttributeValue(elem, name)
|
|
4396
|
+
?.substr(len)
|
|
4397
|
+
.toLowerCase() === value && next(elem);
|
|
4413
4398
|
}
|
|
4414
|
-
return (elem) =>
|
|
4415
|
-
|
|
4416
|
-
return !!((_a = adapter.getAttributeValue(elem, name)) === null || _a === void 0 ? void 0 : _a.endsWith(value)) &&
|
|
4417
|
-
next(elem);
|
|
4418
|
-
};
|
|
4399
|
+
return (elem) => !!adapter.getAttributeValue(elem, name)?.endsWith(value) &&
|
|
4400
|
+
next(elem);
|
|
4419
4401
|
},
|
|
4420
4402
|
any(next, data, options) {
|
|
4421
4403
|
const { adapter } = options;
|
|
4422
4404
|
const { name, value } = data;
|
|
4423
4405
|
if (value === "") {
|
|
4424
|
-
return
|
|
4406
|
+
return boolbaseExports.falseFunc;
|
|
4425
4407
|
}
|
|
4426
4408
|
if (shouldIgnoreCase(data, options)) {
|
|
4427
4409
|
const regex = new RegExp(escapeRegex(value), "i");
|
|
@@ -4433,11 +4415,8 @@ const attributeRules = {
|
|
|
4433
4415
|
next(elem));
|
|
4434
4416
|
};
|
|
4435
4417
|
}
|
|
4436
|
-
return (elem) =>
|
|
4437
|
-
|
|
4438
|
-
return !!((_a = adapter.getAttributeValue(elem, name)) === null || _a === void 0 ? void 0 : _a.includes(value)) &&
|
|
4439
|
-
next(elem);
|
|
4440
|
-
};
|
|
4418
|
+
return (elem) => !!adapter.getAttributeValue(elem, name)?.includes(value) &&
|
|
4419
|
+
next(elem);
|
|
4441
4420
|
},
|
|
4442
4421
|
not(next, data, options) {
|
|
4443
4422
|
const { adapter } = options;
|
|
@@ -4446,7 +4425,7 @@ const attributeRules = {
|
|
|
4446
4425
|
if (value === "") {
|
|
4447
4426
|
return (elem) => !!adapter.getAttributeValue(elem, name) && next(elem);
|
|
4448
4427
|
}
|
|
4449
|
-
|
|
4428
|
+
if (shouldIgnoreCase(data, options)) {
|
|
4450
4429
|
value = value.toLowerCase();
|
|
4451
4430
|
return (elem) => {
|
|
4452
4431
|
const attr = adapter.getAttributeValue(elem, name);
|
|
@@ -4460,6 +4439,169 @@ const attributeRules = {
|
|
|
4460
4439
|
},
|
|
4461
4440
|
};
|
|
4462
4441
|
|
|
4442
|
+
/**
|
|
4443
|
+
* Find all elements matching the query. If not in XML mode, the query will ignore
|
|
4444
|
+
* the contents of `<template>` elements.
|
|
4445
|
+
*
|
|
4446
|
+
* @param query - Function that returns true if the element matches the query.
|
|
4447
|
+
* @param elems - Nodes to query. If a node is an element, its children will be queried.
|
|
4448
|
+
* @param options - Options for querying the document.
|
|
4449
|
+
* @returns All matching elements.
|
|
4450
|
+
*/
|
|
4451
|
+
function findAll(query, elems, options) {
|
|
4452
|
+
const { adapter, xmlMode = false } = options;
|
|
4453
|
+
const result = [];
|
|
4454
|
+
/** Stack of the arrays we are looking at. */
|
|
4455
|
+
const nodeStack = [elems];
|
|
4456
|
+
/** Stack of the indices within the arrays. */
|
|
4457
|
+
const indexStack = [0];
|
|
4458
|
+
for (;;) {
|
|
4459
|
+
// First, check if the current array has any more elements to look at.
|
|
4460
|
+
if (indexStack[0] >= nodeStack[0].length) {
|
|
4461
|
+
// If we have no more arrays to look at, we are done.
|
|
4462
|
+
if (nodeStack.length === 1) {
|
|
4463
|
+
return result;
|
|
4464
|
+
}
|
|
4465
|
+
nodeStack.shift();
|
|
4466
|
+
indexStack.shift();
|
|
4467
|
+
// Loop back to the start to continue with the next array.
|
|
4468
|
+
continue;
|
|
4469
|
+
}
|
|
4470
|
+
const elem = nodeStack[0][indexStack[0]++];
|
|
4471
|
+
if (!adapter.isTag(elem)) {
|
|
4472
|
+
continue;
|
|
4473
|
+
}
|
|
4474
|
+
if (query(elem)) {
|
|
4475
|
+
result.push(elem);
|
|
4476
|
+
}
|
|
4477
|
+
if (xmlMode || adapter.getName(elem) !== "template") {
|
|
4478
|
+
/*
|
|
4479
|
+
* Add the children to the stack. We are depth-first, so this is
|
|
4480
|
+
* the next array we look at.
|
|
4481
|
+
*/
|
|
4482
|
+
const children = adapter.getChildren(elem);
|
|
4483
|
+
if (children.length > 0) {
|
|
4484
|
+
nodeStack.unshift(children);
|
|
4485
|
+
indexStack.unshift(0);
|
|
4486
|
+
}
|
|
4487
|
+
}
|
|
4488
|
+
}
|
|
4489
|
+
}
|
|
4490
|
+
/**
|
|
4491
|
+
* Find the first element matching the query. If not in XML mode, the query will ignore
|
|
4492
|
+
* the contents of `<template>` elements.
|
|
4493
|
+
*
|
|
4494
|
+
* @param query - Function that returns true if the element matches the query.
|
|
4495
|
+
* @param elems - Nodes to query. If a node is an element, its children will be queried.
|
|
4496
|
+
* @param options - Options for querying the document.
|
|
4497
|
+
* @returns The first matching element, or null if there was no match.
|
|
4498
|
+
*/
|
|
4499
|
+
function findOne(query, elems, options) {
|
|
4500
|
+
const { adapter, xmlMode = false } = options;
|
|
4501
|
+
/** Stack of the arrays we are looking at. */
|
|
4502
|
+
const nodeStack = [elems];
|
|
4503
|
+
/** Stack of the indices within the arrays. */
|
|
4504
|
+
const indexStack = [0];
|
|
4505
|
+
for (;;) {
|
|
4506
|
+
// First, check if the current array has any more elements to look at.
|
|
4507
|
+
if (indexStack[0] >= nodeStack[0].length) {
|
|
4508
|
+
// If we have no more arrays to look at, we are done.
|
|
4509
|
+
if (nodeStack.length === 1) {
|
|
4510
|
+
return null;
|
|
4511
|
+
}
|
|
4512
|
+
nodeStack.shift();
|
|
4513
|
+
indexStack.shift();
|
|
4514
|
+
// Loop back to the start to continue with the next array.
|
|
4515
|
+
continue;
|
|
4516
|
+
}
|
|
4517
|
+
const elem = nodeStack[0][indexStack[0]++];
|
|
4518
|
+
if (!adapter.isTag(elem)) {
|
|
4519
|
+
continue;
|
|
4520
|
+
}
|
|
4521
|
+
if (query(elem)) {
|
|
4522
|
+
return elem;
|
|
4523
|
+
}
|
|
4524
|
+
if (xmlMode || adapter.getName(elem) !== "template") {
|
|
4525
|
+
/*
|
|
4526
|
+
* Add the children to the stack. We are depth-first, so this is
|
|
4527
|
+
* the next array we look at.
|
|
4528
|
+
*/
|
|
4529
|
+
const children = adapter.getChildren(elem);
|
|
4530
|
+
if (children.length > 0) {
|
|
4531
|
+
nodeStack.unshift(children);
|
|
4532
|
+
indexStack.unshift(0);
|
|
4533
|
+
}
|
|
4534
|
+
}
|
|
4535
|
+
}
|
|
4536
|
+
}
|
|
4537
|
+
function getNextSiblings(elem, adapter) {
|
|
4538
|
+
const siblings = adapter.getSiblings(elem);
|
|
4539
|
+
if (siblings.length <= 1) {
|
|
4540
|
+
return [];
|
|
4541
|
+
}
|
|
4542
|
+
const elemIndex = siblings.indexOf(elem);
|
|
4543
|
+
if (elemIndex < 0 || elemIndex === siblings.length - 1) {
|
|
4544
|
+
return [];
|
|
4545
|
+
}
|
|
4546
|
+
return siblings.slice(elemIndex + 1).filter(adapter.isTag);
|
|
4547
|
+
}
|
|
4548
|
+
function getElementParent(node, adapter) {
|
|
4549
|
+
const parent = adapter.getParent(node);
|
|
4550
|
+
return parent != null && adapter.isTag(parent) ? parent : null;
|
|
4551
|
+
}
|
|
4552
|
+
|
|
4553
|
+
/**
|
|
4554
|
+
* Only text controls can be made read-only, since for other controls (such
|
|
4555
|
+
* as checkboxes and buttons) there is no useful distinction between being
|
|
4556
|
+
* read-only and being disabled.
|
|
4557
|
+
*
|
|
4558
|
+
* @see {@link https://html.spec.whatwg.org/multipage/input.html#attr-input-readonly}
|
|
4559
|
+
*/
|
|
4560
|
+
const textControl = "input:is([type=text i],[type=search i],[type=url i],[type=tel i],[type=email i],[type=password i],[type=date i],[type=month i],[type=week i],[type=time i],[type=datetime-local i],[type=number i])";
|
|
4561
|
+
/**
|
|
4562
|
+
* Aliases are pseudos that are expressed as selectors.
|
|
4563
|
+
*/
|
|
4564
|
+
const aliases = {
|
|
4565
|
+
// Links
|
|
4566
|
+
"any-link": ":is(a, area, link)[href]",
|
|
4567
|
+
link: ":any-link:not(:visited)",
|
|
4568
|
+
// Forms
|
|
4569
|
+
// https://html.spec.whatwg.org/multipage/scripting.html#disabled-elements
|
|
4570
|
+
disabled: `:is(
|
|
4571
|
+
:is(button, input, select, textarea, optgroup, option)[disabled],
|
|
4572
|
+
optgroup[disabled] > option,
|
|
4573
|
+
fieldset[disabled]:not(fieldset[disabled] legend:first-of-type *)
|
|
4574
|
+
)`,
|
|
4575
|
+
enabled: ":not(:disabled)",
|
|
4576
|
+
checked: ":is(:is(input[type=radio], input[type=checkbox])[checked], :selected)",
|
|
4577
|
+
required: ":is(input, select, textarea)[required]",
|
|
4578
|
+
optional: ":is(input, select, textarea):not([required])",
|
|
4579
|
+
"read-only": `[readonly]:is(textarea, ${textControl})`,
|
|
4580
|
+
"read-write": `:not([readonly]):is(textarea, ${textControl})`,
|
|
4581
|
+
// JQuery extensions
|
|
4582
|
+
/**
|
|
4583
|
+
* `:selected` matches option elements that have the `selected` attribute,
|
|
4584
|
+
* or are the first option element in a select element that does not have
|
|
4585
|
+
* the `multiple` attribute and does not have any option elements with the
|
|
4586
|
+
* `selected` attribute.
|
|
4587
|
+
*
|
|
4588
|
+
* @see https://html.spec.whatwg.org/multipage/form-elements.html#concept-option-selectedness
|
|
4589
|
+
*/
|
|
4590
|
+
selected: "option:is([selected], select:not([multiple]):not(:has(> option[selected])) > :first-of-type)",
|
|
4591
|
+
checkbox: "[type=checkbox]",
|
|
4592
|
+
file: "[type=file]",
|
|
4593
|
+
password: "[type=password]",
|
|
4594
|
+
radio: "[type=radio]",
|
|
4595
|
+
reset: "[type=reset]",
|
|
4596
|
+
image: "[type=image]",
|
|
4597
|
+
submit: "[type=submit]",
|
|
4598
|
+
parent: ":not(:empty)",
|
|
4599
|
+
header: ":is(h1, h2, h3, h4, h5, h6)",
|
|
4600
|
+
button: ":is(button, input[type=button])",
|
|
4601
|
+
input: ":is(input, textarea, select, button)",
|
|
4602
|
+
text: "input:is(:not([type!='']), [type=text])",
|
|
4603
|
+
};
|
|
4604
|
+
|
|
4463
4605
|
// Following http://www.w3.org/TR/css3-selectors/#nth-child-pseudo
|
|
4464
4606
|
// Whitespace as per https://www.w3.org/TR/selectors-3/#lex is " \t\r\n\f"
|
|
4465
4607
|
const whitespace = new Set([9, 10, 12, 13, 32]);
|
|
@@ -4614,38 +4756,73 @@ function nthCheck(formula) {
|
|
|
4614
4756
|
return compile(parse(formula));
|
|
4615
4757
|
}
|
|
4616
4758
|
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4759
|
+
/**
|
|
4760
|
+
* Some selectors such as `:contains` and (non-relative) `:has` will only be
|
|
4761
|
+
* able to match elements if their parents match the selector (as they contain
|
|
4762
|
+
* a subset of the elements that the parent contains).
|
|
4763
|
+
*
|
|
4764
|
+
* This function wraps the given `matches` function in a function that caches
|
|
4765
|
+
* the results of the parent elements, so that the `matches` function only
|
|
4766
|
+
* needs to be called once for each subtree.
|
|
4767
|
+
*/
|
|
4768
|
+
function cacheParentResults(next, { adapter, cacheResults }, matches) {
|
|
4769
|
+
if (cacheResults === false || typeof WeakMap === "undefined") {
|
|
4770
|
+
return (elem) => next(elem) && matches(elem);
|
|
4771
|
+
}
|
|
4772
|
+
// Use a cache to avoid re-checking children of an element.
|
|
4773
|
+
// @ts-expect-error `Node` is not extending object
|
|
4774
|
+
const resultCache = new WeakMap();
|
|
4775
|
+
function addResultToCache(elem) {
|
|
4776
|
+
const result = matches(elem);
|
|
4777
|
+
resultCache.set(elem, result);
|
|
4778
|
+
return result;
|
|
4779
|
+
}
|
|
4780
|
+
return function cachedMatcher(elem) {
|
|
4781
|
+
if (!next(elem)) {
|
|
4782
|
+
return false;
|
|
4783
|
+
}
|
|
4784
|
+
if (resultCache.has(elem)) {
|
|
4785
|
+
return resultCache.get(elem);
|
|
4786
|
+
}
|
|
4787
|
+
// Check all of the element's parents.
|
|
4788
|
+
let node = elem;
|
|
4789
|
+
do {
|
|
4790
|
+
const parent = getElementParent(node, adapter);
|
|
4791
|
+
if (parent === null) {
|
|
4792
|
+
return addResultToCache(elem);
|
|
4793
|
+
}
|
|
4794
|
+
node = parent;
|
|
4795
|
+
} while (!resultCache.has(node));
|
|
4796
|
+
return resultCache.get(node) && addResultToCache(elem);
|
|
4621
4797
|
};
|
|
4622
4798
|
}
|
|
4799
|
+
|
|
4623
4800
|
const filters = {
|
|
4624
|
-
contains(next, text,
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
};
|
|
4801
|
+
contains(next, text, options) {
|
|
4802
|
+
const { getText } = options.adapter;
|
|
4803
|
+
return cacheParentResults(next, options, (elem) => getText(elem).includes(text));
|
|
4628
4804
|
},
|
|
4629
|
-
icontains(next, text,
|
|
4805
|
+
icontains(next, text, options) {
|
|
4630
4806
|
const itext = text.toLowerCase();
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
adapter.getText(elem).toLowerCase().includes(itext));
|
|
4634
|
-
};
|
|
4807
|
+
const { getText } = options.adapter;
|
|
4808
|
+
return cacheParentResults(next, options, (elem) => getText(elem).toLowerCase().includes(itext));
|
|
4635
4809
|
},
|
|
4636
4810
|
// Location specific methods
|
|
4637
4811
|
"nth-child"(next, rule, { adapter, equals }) {
|
|
4638
4812
|
const func = nthCheck(rule);
|
|
4639
|
-
if (func ===
|
|
4640
|
-
return
|
|
4641
|
-
|
|
4642
|
-
|
|
4813
|
+
if (func === boolbaseExports.falseFunc) {
|
|
4814
|
+
return boolbaseExports.falseFunc;
|
|
4815
|
+
}
|
|
4816
|
+
if (func === boolbaseExports.trueFunc) {
|
|
4817
|
+
return (elem) => getElementParent(elem, adapter) !== null && next(elem);
|
|
4818
|
+
}
|
|
4643
4819
|
return function nthChild(elem) {
|
|
4644
4820
|
const siblings = adapter.getSiblings(elem);
|
|
4645
4821
|
let pos = 0;
|
|
4646
4822
|
for (let i = 0; i < siblings.length; i++) {
|
|
4647
|
-
if (equals(elem, siblings[i]))
|
|
4823
|
+
if (equals(elem, siblings[i])) {
|
|
4648
4824
|
break;
|
|
4825
|
+
}
|
|
4649
4826
|
if (adapter.isTag(siblings[i])) {
|
|
4650
4827
|
pos++;
|
|
4651
4828
|
}
|
|
@@ -4655,16 +4832,19 @@ const filters = {
|
|
|
4655
4832
|
},
|
|
4656
4833
|
"nth-last-child"(next, rule, { adapter, equals }) {
|
|
4657
4834
|
const func = nthCheck(rule);
|
|
4658
|
-
if (func ===
|
|
4659
|
-
return
|
|
4660
|
-
|
|
4661
|
-
|
|
4835
|
+
if (func === boolbaseExports.falseFunc) {
|
|
4836
|
+
return boolbaseExports.falseFunc;
|
|
4837
|
+
}
|
|
4838
|
+
if (func === boolbaseExports.trueFunc) {
|
|
4839
|
+
return (elem) => getElementParent(elem, adapter) !== null && next(elem);
|
|
4840
|
+
}
|
|
4662
4841
|
return function nthLastChild(elem) {
|
|
4663
4842
|
const siblings = adapter.getSiblings(elem);
|
|
4664
4843
|
let pos = 0;
|
|
4665
4844
|
for (let i = siblings.length - 1; i >= 0; i--) {
|
|
4666
|
-
if (equals(elem, siblings[i]))
|
|
4845
|
+
if (equals(elem, siblings[i])) {
|
|
4667
4846
|
break;
|
|
4847
|
+
}
|
|
4668
4848
|
if (adapter.isTag(siblings[i])) {
|
|
4669
4849
|
pos++;
|
|
4670
4850
|
}
|
|
@@ -4674,17 +4854,20 @@ const filters = {
|
|
|
4674
4854
|
},
|
|
4675
4855
|
"nth-of-type"(next, rule, { adapter, equals }) {
|
|
4676
4856
|
const func = nthCheck(rule);
|
|
4677
|
-
if (func ===
|
|
4678
|
-
return
|
|
4679
|
-
|
|
4680
|
-
|
|
4857
|
+
if (func === boolbaseExports.falseFunc) {
|
|
4858
|
+
return boolbaseExports.falseFunc;
|
|
4859
|
+
}
|
|
4860
|
+
if (func === boolbaseExports.trueFunc) {
|
|
4861
|
+
return (elem) => getElementParent(elem, adapter) !== null && next(elem);
|
|
4862
|
+
}
|
|
4681
4863
|
return function nthOfType(elem) {
|
|
4682
4864
|
const siblings = adapter.getSiblings(elem);
|
|
4683
4865
|
let pos = 0;
|
|
4684
4866
|
for (let i = 0; i < siblings.length; i++) {
|
|
4685
4867
|
const currentSibling = siblings[i];
|
|
4686
|
-
if (equals(elem, currentSibling))
|
|
4868
|
+
if (equals(elem, currentSibling)) {
|
|
4687
4869
|
break;
|
|
4870
|
+
}
|
|
4688
4871
|
if (adapter.isTag(currentSibling) &&
|
|
4689
4872
|
adapter.getName(currentSibling) === adapter.getName(elem)) {
|
|
4690
4873
|
pos++;
|
|
@@ -4695,17 +4878,20 @@ const filters = {
|
|
|
4695
4878
|
},
|
|
4696
4879
|
"nth-last-of-type"(next, rule, { adapter, equals }) {
|
|
4697
4880
|
const func = nthCheck(rule);
|
|
4698
|
-
if (func ===
|
|
4699
|
-
return
|
|
4700
|
-
|
|
4701
|
-
|
|
4881
|
+
if (func === boolbaseExports.falseFunc) {
|
|
4882
|
+
return boolbaseExports.falseFunc;
|
|
4883
|
+
}
|
|
4884
|
+
if (func === boolbaseExports.trueFunc) {
|
|
4885
|
+
return (elem) => getElementParent(elem, adapter) !== null && next(elem);
|
|
4886
|
+
}
|
|
4702
4887
|
return function nthLastOfType(elem) {
|
|
4703
4888
|
const siblings = adapter.getSiblings(elem);
|
|
4704
4889
|
let pos = 0;
|
|
4705
4890
|
for (let i = siblings.length - 1; i >= 0; i--) {
|
|
4706
4891
|
const currentSibling = siblings[i];
|
|
4707
|
-
if (equals(elem, currentSibling))
|
|
4892
|
+
if (equals(elem, currentSibling)) {
|
|
4708
4893
|
break;
|
|
4894
|
+
}
|
|
4709
4895
|
if (adapter.isTag(currentSibling) &&
|
|
4710
4896
|
adapter.getName(currentSibling) === adapter.getName(elem)) {
|
|
4711
4897
|
pos++;
|
|
@@ -4716,10 +4902,7 @@ const filters = {
|
|
|
4716
4902
|
},
|
|
4717
4903
|
// TODO determine the actual root element
|
|
4718
4904
|
root(next, _rule, { adapter }) {
|
|
4719
|
-
return (elem) =>
|
|
4720
|
-
const parent = adapter.getParent(elem);
|
|
4721
|
-
return (parent == null || !adapter.isTag(parent)) && next(elem);
|
|
4722
|
-
};
|
|
4905
|
+
return (elem) => getElementParent(elem, adapter) === null && next(elem);
|
|
4723
4906
|
},
|
|
4724
4907
|
scope(next, rule, options, context) {
|
|
4725
4908
|
const { equals } = options;
|
|
@@ -4747,7 +4930,7 @@ function dynamicStatePseudo(name) {
|
|
|
4747
4930
|
return function dynamicPseudo(next, _rule, { adapter }) {
|
|
4748
4931
|
const func = adapter[name];
|
|
4749
4932
|
if (typeof func !== "function") {
|
|
4750
|
-
return
|
|
4933
|
+
return boolbaseExports.falseFunc;
|
|
4751
4934
|
}
|
|
4752
4935
|
return function active(elem) {
|
|
4753
4936
|
return func(elem) && next(elem);
|
|
@@ -4755,12 +4938,25 @@ function dynamicStatePseudo(name) {
|
|
|
4755
4938
|
};
|
|
4756
4939
|
}
|
|
4757
4940
|
|
|
4941
|
+
/**
|
|
4942
|
+
* CSS limits the characters considered as whitespace to space, tab & line
|
|
4943
|
+
* feed. We add carriage returns as htmlparser2 doesn't normalize them to
|
|
4944
|
+
* line feeds.
|
|
4945
|
+
*
|
|
4946
|
+
* @see {@link https://www.w3.org/TR/css-text-3/#white-space}
|
|
4947
|
+
*/
|
|
4948
|
+
const isDocumentWhiteSpace = /^[ \t\r\n]*$/;
|
|
4758
4949
|
// While filters are precompiled, pseudos get called when they are needed
|
|
4759
4950
|
const pseudos = {
|
|
4760
4951
|
empty(elem, { adapter }) {
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4952
|
+
const children = adapter.getChildren(elem);
|
|
4953
|
+
return (
|
|
4954
|
+
// First, make sure the tag does not have any element children.
|
|
4955
|
+
children.every((elem) => !adapter.isTag(elem)) &&
|
|
4956
|
+
// Then, check that the text content is only whitespace.
|
|
4957
|
+
children.every((elem) =>
|
|
4958
|
+
// FIXME: `getText` call is potentially expensive.
|
|
4959
|
+
isDocumentWhiteSpace.test(adapter.getText(elem))));
|
|
4764
4960
|
},
|
|
4765
4961
|
"first-child"(elem, { adapter, equals }) {
|
|
4766
4962
|
if (adapter.prevElementSibling) {
|
|
@@ -4774,10 +4970,12 @@ const pseudos = {
|
|
|
4774
4970
|
"last-child"(elem, { adapter, equals }) {
|
|
4775
4971
|
const siblings = adapter.getSiblings(elem);
|
|
4776
4972
|
for (let i = siblings.length - 1; i >= 0; i--) {
|
|
4777
|
-
if (equals(elem, siblings[i]))
|
|
4973
|
+
if (equals(elem, siblings[i])) {
|
|
4778
4974
|
return true;
|
|
4779
|
-
|
|
4975
|
+
}
|
|
4976
|
+
if (adapter.isTag(siblings[i])) {
|
|
4780
4977
|
break;
|
|
4978
|
+
}
|
|
4781
4979
|
}
|
|
4782
4980
|
return false;
|
|
4783
4981
|
},
|
|
@@ -4786,8 +4984,9 @@ const pseudos = {
|
|
|
4786
4984
|
const elemName = adapter.getName(elem);
|
|
4787
4985
|
for (let i = 0; i < siblings.length; i++) {
|
|
4788
4986
|
const currentSibling = siblings[i];
|
|
4789
|
-
if (equals(elem, currentSibling))
|
|
4987
|
+
if (equals(elem, currentSibling)) {
|
|
4790
4988
|
return true;
|
|
4989
|
+
}
|
|
4791
4990
|
if (adapter.isTag(currentSibling) &&
|
|
4792
4991
|
adapter.getName(currentSibling) === elemName) {
|
|
4793
4992
|
break;
|
|
@@ -4800,8 +4999,9 @@ const pseudos = {
|
|
|
4800
4999
|
const elemName = adapter.getName(elem);
|
|
4801
5000
|
for (let i = siblings.length - 1; i >= 0; i--) {
|
|
4802
5001
|
const currentSibling = siblings[i];
|
|
4803
|
-
if (equals(elem, currentSibling))
|
|
5002
|
+
if (equals(elem, currentSibling)) {
|
|
4804
5003
|
return true;
|
|
5004
|
+
}
|
|
4805
5005
|
if (adapter.isTag(currentSibling) &&
|
|
4806
5006
|
adapter.getName(currentSibling) === elemName) {
|
|
4807
5007
|
break;
|
|
@@ -4834,56 +5034,123 @@ function verifyPseudoArgs(func, name, subselect, argIndex) {
|
|
|
4834
5034
|
}
|
|
4835
5035
|
}
|
|
4836
5036
|
|
|
5037
|
+
function isTraversal(token) {
|
|
5038
|
+
return token.type === "_flexibleDescendant" || isTraversal$1(token);
|
|
5039
|
+
}
|
|
4837
5040
|
/**
|
|
4838
|
-
*
|
|
5041
|
+
* Sort the parts of the passed selector, as there is potential for
|
|
5042
|
+
* optimization (some types of selectors are faster than others).
|
|
5043
|
+
*
|
|
5044
|
+
* @param arr Selector to sort
|
|
4839
5045
|
*/
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
5046
|
+
function sortRules(arr) {
|
|
5047
|
+
const ratings = arr.map(getQuality);
|
|
5048
|
+
for (let i = 1; i < arr.length; i++) {
|
|
5049
|
+
const procNew = ratings[i];
|
|
5050
|
+
if (procNew < 0) {
|
|
5051
|
+
continue;
|
|
5052
|
+
}
|
|
5053
|
+
// Use insertion sort to move the token to the correct position.
|
|
5054
|
+
for (let j = i; j > 0 && procNew < ratings[j - 1]; j--) {
|
|
5055
|
+
const token = arr[j];
|
|
5056
|
+
arr[j] = arr[j - 1];
|
|
5057
|
+
arr[j - 1] = token;
|
|
5058
|
+
ratings[j] = ratings[j - 1];
|
|
5059
|
+
ratings[j - 1] = procNew;
|
|
5060
|
+
}
|
|
5061
|
+
}
|
|
5062
|
+
}
|
|
5063
|
+
function getAttributeQuality(token) {
|
|
5064
|
+
switch (token.action) {
|
|
5065
|
+
case AttributeAction.Exists: {
|
|
5066
|
+
return 10;
|
|
5067
|
+
}
|
|
5068
|
+
case AttributeAction.Equals: {
|
|
5069
|
+
// Prefer ID selectors (eg. #ID)
|
|
5070
|
+
return token.name === "id" ? 9 : 8;
|
|
5071
|
+
}
|
|
5072
|
+
case AttributeAction.Not: {
|
|
5073
|
+
return 7;
|
|
5074
|
+
}
|
|
5075
|
+
case AttributeAction.Start: {
|
|
5076
|
+
return 6;
|
|
5077
|
+
}
|
|
5078
|
+
case AttributeAction.End: {
|
|
5079
|
+
return 6;
|
|
5080
|
+
}
|
|
5081
|
+
case AttributeAction.Any: {
|
|
5082
|
+
return 5;
|
|
5083
|
+
}
|
|
5084
|
+
case AttributeAction.Hyphen: {
|
|
5085
|
+
return 4;
|
|
5086
|
+
}
|
|
5087
|
+
case AttributeAction.Element: {
|
|
5088
|
+
return 3;
|
|
5089
|
+
}
|
|
5090
|
+
}
|
|
5091
|
+
}
|
|
5092
|
+
/**
|
|
5093
|
+
* Determine the quality of the passed token. The higher the number, the
|
|
5094
|
+
* faster the token is to execute.
|
|
5095
|
+
*
|
|
5096
|
+
* @param token Token to get the quality of.
|
|
5097
|
+
* @returns The token's quality.
|
|
5098
|
+
*/
|
|
5099
|
+
function getQuality(token) {
|
|
5100
|
+
switch (token.type) {
|
|
5101
|
+
case SelectorType.Universal: {
|
|
5102
|
+
return 50;
|
|
5103
|
+
}
|
|
5104
|
+
case SelectorType.Tag: {
|
|
5105
|
+
return 30;
|
|
5106
|
+
}
|
|
5107
|
+
case SelectorType.Attribute: {
|
|
5108
|
+
return Math.floor(getAttributeQuality(token) /
|
|
5109
|
+
// `ignoreCase` adds some overhead, half the result if applicable.
|
|
5110
|
+
(token.ignoreCase ? 2 : 1));
|
|
5111
|
+
}
|
|
5112
|
+
case SelectorType.Pseudo: {
|
|
5113
|
+
return !token.data
|
|
5114
|
+
? 3
|
|
5115
|
+
: token.name === "has" ||
|
|
5116
|
+
token.name === "contains" ||
|
|
5117
|
+
token.name === "icontains"
|
|
5118
|
+
? // Expensive in any case — run as late as possible.
|
|
5119
|
+
0
|
|
5120
|
+
: Array.isArray(token.data)
|
|
5121
|
+
? // Eg. `:is`, `:not`
|
|
5122
|
+
Math.max(
|
|
5123
|
+
// If we have traversals, try to avoid executing this selector
|
|
5124
|
+
0, Math.min(...token.data.map((d) => Math.min(...d.map(getQuality)))))
|
|
5125
|
+
: 2;
|
|
5126
|
+
}
|
|
5127
|
+
default: {
|
|
5128
|
+
return -1;
|
|
5129
|
+
}
|
|
5130
|
+
}
|
|
5131
|
+
}
|
|
5132
|
+
function includesScopePseudo(t) {
|
|
5133
|
+
return (t.type === SelectorType.Pseudo &&
|
|
5134
|
+
(t.name === "scope" ||
|
|
5135
|
+
(Array.isArray(t.data) &&
|
|
5136
|
+
t.data.some((data) => data.some(includesScopePseudo)))));
|
|
5137
|
+
}
|
|
4871
5138
|
|
|
4872
5139
|
/** Used as a placeholder for :has. Will be replaced with the actual element. */
|
|
4873
5140
|
const PLACEHOLDER_ELEMENT = {};
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
5141
|
+
/**
|
|
5142
|
+
* Check if the selector has any properties that rely on the current element.
|
|
5143
|
+
* If not, we can cache the result of the selector.
|
|
5144
|
+
*
|
|
5145
|
+
* We can't cache selectors that start with a traversal (e.g. `>`, `+`, `~`),
|
|
5146
|
+
* or include a `:scope`.
|
|
5147
|
+
*
|
|
5148
|
+
* @param selector - The selector to check.
|
|
5149
|
+
* @returns Whether the selector has any properties that rely on the current element.
|
|
5150
|
+
*/
|
|
5151
|
+
function hasDependsOnCurrentElement(selector) {
|
|
5152
|
+
return selector.some((sel) => sel.length > 0 &&
|
|
5153
|
+
(isTraversal(sel[0]) || sel.some(includesScopePseudo)));
|
|
4887
5154
|
}
|
|
4888
5155
|
function copyOptions(options) {
|
|
4889
5156
|
// Not copied: context, rootFunc
|
|
@@ -4900,10 +5167,10 @@ function copyOptions(options) {
|
|
|
4900
5167
|
}
|
|
4901
5168
|
const is = (next, token, options, context, compileToken) => {
|
|
4902
5169
|
const func = compileToken(token, copyOptions(options), context);
|
|
4903
|
-
return func ===
|
|
5170
|
+
return func === boolbaseExports.trueFunc
|
|
4904
5171
|
? next
|
|
4905
|
-
: func ===
|
|
4906
|
-
?
|
|
5172
|
+
: func === boolbaseExports.falseFunc
|
|
5173
|
+
? boolbaseExports.falseFunc
|
|
4907
5174
|
: (elem) => func(elem) && next(elem);
|
|
4908
5175
|
};
|
|
4909
5176
|
/*
|
|
@@ -4920,10 +5187,10 @@ const subselects = {
|
|
|
4920
5187
|
where: is,
|
|
4921
5188
|
not(next, token, options, context, compileToken) {
|
|
4922
5189
|
const func = compileToken(token, copyOptions(options), context);
|
|
4923
|
-
return func ===
|
|
5190
|
+
return func === boolbaseExports.falseFunc
|
|
4924
5191
|
? next
|
|
4925
|
-
: func ===
|
|
4926
|
-
?
|
|
5192
|
+
: func === boolbaseExports.trueFunc
|
|
5193
|
+
? boolbaseExports.falseFunc
|
|
4927
5194
|
: (elem) => !func(elem) && next(elem);
|
|
4928
5195
|
},
|
|
4929
5196
|
has(next, subselect, options, _context, compileToken) {
|
|
@@ -4934,35 +5201,54 @@ const subselects = {
|
|
|
4934
5201
|
? // Used as a placeholder. Will be replaced with the actual element.
|
|
4935
5202
|
[PLACEHOLDER_ELEMENT]
|
|
4936
5203
|
: undefined;
|
|
5204
|
+
const skipCache = hasDependsOnCurrentElement(subselect);
|
|
4937
5205
|
const compiled = compileToken(subselect, opts, context);
|
|
4938
|
-
if (compiled ===
|
|
4939
|
-
return
|
|
4940
|
-
|
|
5206
|
+
if (compiled === boolbaseExports.falseFunc) {
|
|
5207
|
+
return boolbaseExports.falseFunc;
|
|
5208
|
+
}
|
|
4941
5209
|
// If `compiled` is `trueFunc`, we can skip this.
|
|
4942
|
-
if (context && compiled !==
|
|
4943
|
-
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
return
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
5210
|
+
if (context && compiled !== boolbaseExports.trueFunc) {
|
|
5211
|
+
return skipCache
|
|
5212
|
+
? (elem) => {
|
|
5213
|
+
if (!next(elem)) {
|
|
5214
|
+
return false;
|
|
5215
|
+
}
|
|
5216
|
+
context[0] = elem;
|
|
5217
|
+
const childs = adapter.getChildren(elem);
|
|
5218
|
+
return (findOne(compiled, compiled.shouldTestNextSiblings
|
|
5219
|
+
? [
|
|
5220
|
+
...childs,
|
|
5221
|
+
...getNextSiblings(elem, adapter),
|
|
5222
|
+
]
|
|
5223
|
+
: childs, options) !== null);
|
|
5224
|
+
}
|
|
5225
|
+
: cacheParentResults(next, options, (elem) => {
|
|
5226
|
+
context[0] = elem;
|
|
5227
|
+
return (findOne(compiled, adapter.getChildren(elem), options) !== null);
|
|
5228
|
+
});
|
|
4958
5229
|
}
|
|
4959
|
-
|
|
4960
|
-
|
|
5230
|
+
const hasOne = (elem) => findOne(compiled, adapter.getChildren(elem), options) !== null;
|
|
5231
|
+
return skipCache
|
|
5232
|
+
? (elem) => next(elem) && hasOne(elem)
|
|
5233
|
+
: cacheParentResults(next, options, hasOne);
|
|
4961
5234
|
},
|
|
4962
5235
|
};
|
|
4963
5236
|
|
|
5237
|
+
/*
|
|
5238
|
+
* Pseudo selectors
|
|
5239
|
+
*
|
|
5240
|
+
* Pseudo selectors are available in three forms:
|
|
5241
|
+
*
|
|
5242
|
+
* 1. Filters are called when the selector is compiled and return a function
|
|
5243
|
+
* that has to return either false, or the results of `next()`.
|
|
5244
|
+
* 2. Pseudos are called on execution. They have to return a boolean.
|
|
5245
|
+
* 3. Subselects work like filters, but have an embedded selector that will be run separately.
|
|
5246
|
+
*
|
|
5247
|
+
* Filters are great if you want to do some pre-processing, or change the call order
|
|
5248
|
+
* of `next()` and your code.
|
|
5249
|
+
* Pseudos should be used to implement simple checks.
|
|
5250
|
+
*/
|
|
4964
5251
|
function compilePseudoSelector(next, selector, options, context, compileToken) {
|
|
4965
|
-
var _a;
|
|
4966
5252
|
const { name, data } = selector;
|
|
4967
5253
|
if (Array.isArray(data)) {
|
|
4968
5254
|
if (!(name in subselects)) {
|
|
@@ -4970,7 +5256,7 @@ function compilePseudoSelector(next, selector, options, context, compileToken) {
|
|
|
4970
5256
|
}
|
|
4971
5257
|
return subselects[name](next, data, options, context, compileToken);
|
|
4972
5258
|
}
|
|
4973
|
-
const userPseudo =
|
|
5259
|
+
const userPseudo = options.pseudos?.[name];
|
|
4974
5260
|
const stringPseudo = typeof userPseudo === "string" ? userPseudo : aliases[name];
|
|
4975
5261
|
if (typeof stringPseudo === "string") {
|
|
4976
5262
|
if (data != null) {
|
|
@@ -4995,18 +5281,11 @@ function compilePseudoSelector(next, selector, options, context, compileToken) {
|
|
|
4995
5281
|
throw new Error(`Unknown pseudo-class :${name}`);
|
|
4996
5282
|
}
|
|
4997
5283
|
|
|
4998
|
-
function getElementParent(node, adapter) {
|
|
4999
|
-
const parent = adapter.getParent(node);
|
|
5000
|
-
if (parent && adapter.isTag(parent)) {
|
|
5001
|
-
return parent;
|
|
5002
|
-
}
|
|
5003
|
-
return null;
|
|
5004
|
-
}
|
|
5005
5284
|
/*
|
|
5006
5285
|
* All available rules
|
|
5007
5286
|
*/
|
|
5008
|
-
function compileGeneralSelector(next, selector, options, context, compileToken) {
|
|
5009
|
-
const { adapter, equals } = options;
|
|
5287
|
+
function compileGeneralSelector(next, selector, options, context, compileToken, hasExpensiveSubselector) {
|
|
5288
|
+
const { adapter, equals, cacheResults } = options;
|
|
5010
5289
|
switch (selector.type) {
|
|
5011
5290
|
case SelectorType.PseudoElement: {
|
|
5012
5291
|
throw new Error("Pseudo-elements are not supported by css-select");
|
|
@@ -5041,10 +5320,12 @@ function compileGeneralSelector(next, selector, options, context, compileToken)
|
|
|
5041
5320
|
}
|
|
5042
5321
|
// Traversal
|
|
5043
5322
|
case SelectorType.Descendant: {
|
|
5044
|
-
if (
|
|
5045
|
-
|
|
5323
|
+
if (!hasExpensiveSubselector ||
|
|
5324
|
+
cacheResults === false ||
|
|
5325
|
+
typeof WeakMap === "undefined") {
|
|
5046
5326
|
return function descendant(elem) {
|
|
5047
5327
|
let current = elem;
|
|
5328
|
+
// biome-ignore lint/suspicious/noAssignInExpressions: TODO
|
|
5048
5329
|
while ((current = getElementParent(current, adapter))) {
|
|
5049
5330
|
if (next(current)) {
|
|
5050
5331
|
return true;
|
|
@@ -5053,16 +5334,26 @@ function compileGeneralSelector(next, selector, options, context, compileToken)
|
|
|
5053
5334
|
return false;
|
|
5054
5335
|
};
|
|
5055
5336
|
}
|
|
5056
|
-
|
|
5057
|
-
const isFalseCache = new WeakSet();
|
|
5337
|
+
const resultCache = new WeakMap();
|
|
5058
5338
|
return function cachedDescendant(elem) {
|
|
5059
5339
|
let current = elem;
|
|
5340
|
+
let result;
|
|
5341
|
+
// biome-ignore lint/suspicious/noAssignInExpressions: TODO
|
|
5060
5342
|
while ((current = getElementParent(current, adapter))) {
|
|
5061
|
-
|
|
5062
|
-
|
|
5343
|
+
const cached = resultCache.get(current);
|
|
5344
|
+
if (cached === undefined) {
|
|
5345
|
+
result ?? (result = { matches: false });
|
|
5346
|
+
result.matches = next(current);
|
|
5347
|
+
resultCache.set(current, result);
|
|
5348
|
+
if (result.matches) {
|
|
5063
5349
|
return true;
|
|
5064
5350
|
}
|
|
5065
|
-
|
|
5351
|
+
}
|
|
5352
|
+
else {
|
|
5353
|
+
if (result) {
|
|
5354
|
+
result.matches = cached.matches;
|
|
5355
|
+
}
|
|
5356
|
+
return cached.matches;
|
|
5066
5357
|
}
|
|
5067
5358
|
}
|
|
5068
5359
|
return false;
|
|
@@ -5073,9 +5364,11 @@ function compileGeneralSelector(next, selector, options, context, compileToken)
|
|
|
5073
5364
|
return function flexibleDescendant(elem) {
|
|
5074
5365
|
let current = elem;
|
|
5075
5366
|
do {
|
|
5076
|
-
if (next(current))
|
|
5367
|
+
if (next(current)) {
|
|
5077
5368
|
return true;
|
|
5078
|
-
|
|
5369
|
+
}
|
|
5370
|
+
current = getElementParent(current, adapter);
|
|
5371
|
+
} while (current);
|
|
5079
5372
|
return false;
|
|
5080
5373
|
};
|
|
5081
5374
|
}
|
|
@@ -5088,8 +5381,8 @@ function compileGeneralSelector(next, selector, options, context, compileToken)
|
|
|
5088
5381
|
}
|
|
5089
5382
|
case SelectorType.Child: {
|
|
5090
5383
|
return function child(elem) {
|
|
5091
|
-
const parent =
|
|
5092
|
-
return parent
|
|
5384
|
+
const parent = getElementParent(elem, adapter);
|
|
5385
|
+
return parent !== null && next(parent);
|
|
5093
5386
|
};
|
|
5094
5387
|
}
|
|
5095
5388
|
case SelectorType.Sibling: {
|
|
@@ -5097,8 +5390,9 @@ function compileGeneralSelector(next, selector, options, context, compileToken)
|
|
|
5097
5390
|
const siblings = adapter.getSiblings(elem);
|
|
5098
5391
|
for (let i = 0; i < siblings.length; i++) {
|
|
5099
5392
|
const currentSibling = siblings[i];
|
|
5100
|
-
if (equals(elem, currentSibling))
|
|
5393
|
+
if (equals(elem, currentSibling)) {
|
|
5101
5394
|
break;
|
|
5395
|
+
}
|
|
5102
5396
|
if (adapter.isTag(currentSibling) && next(currentSibling)) {
|
|
5103
5397
|
return true;
|
|
5104
5398
|
}
|
|
@@ -5118,8 +5412,9 @@ function compileGeneralSelector(next, selector, options, context, compileToken)
|
|
|
5118
5412
|
let lastElement;
|
|
5119
5413
|
for (let i = 0; i < siblings.length; i++) {
|
|
5120
5414
|
const currentSibling = siblings[i];
|
|
5121
|
-
if (equals(elem, currentSibling))
|
|
5415
|
+
if (equals(elem, currentSibling)) {
|
|
5122
5416
|
break;
|
|
5417
|
+
}
|
|
5123
5418
|
if (adapter.isTag(currentSibling)) {
|
|
5124
5419
|
lastElement = currentSibling;
|
|
5125
5420
|
}
|
|
@@ -5136,16 +5431,6 @@ function compileGeneralSelector(next, selector, options, context, compileToken)
|
|
|
5136
5431
|
}
|
|
5137
5432
|
}
|
|
5138
5433
|
|
|
5139
|
-
function compileUnsafe(selector, options, context) {
|
|
5140
|
-
const token = typeof selector === "string" ? parse$1(selector) : selector;
|
|
5141
|
-
return compileToken(token, options, context);
|
|
5142
|
-
}
|
|
5143
|
-
function includesScopePseudo(t) {
|
|
5144
|
-
return (t.type === SelectorType.Pseudo &&
|
|
5145
|
-
(t.name === "scope" ||
|
|
5146
|
-
(Array.isArray(t.data) &&
|
|
5147
|
-
t.data.some((data) => data.some(includesScopePseudo)))));
|
|
5148
|
-
}
|
|
5149
5434
|
const DESCENDANT_TOKEN = { type: SelectorType.Descendant };
|
|
5150
5435
|
const FLEXIBLE_DESCENDANT_TOKEN = {
|
|
5151
5436
|
type: "_flexibleDescendant",
|
|
@@ -5161,10 +5446,8 @@ const SCOPE_TOKEN = {
|
|
|
5161
5446
|
*/
|
|
5162
5447
|
function absolutize(token, { adapter }, context) {
|
|
5163
5448
|
// TODO Use better check if the context is a document
|
|
5164
|
-
const hasContext = !!
|
|
5165
|
-
|
|
5166
|
-
return e === PLACEHOLDER_ELEMENT || (parent && adapter.isTag(parent));
|
|
5167
|
-
}));
|
|
5449
|
+
const hasContext = !!context?.every((e) => e === PLACEHOLDER_ELEMENT ||
|
|
5450
|
+
(adapter.isTag(e) && getElementParent(e, adapter) !== null));
|
|
5168
5451
|
for (const t of token) {
|
|
5169
5452
|
if (t.length > 0 &&
|
|
5170
5453
|
isTraversal(t[0]) &&
|
|
@@ -5178,10 +5461,9 @@ function absolutize(token, { adapter }, context) {
|
|
|
5178
5461
|
t.unshift(SCOPE_TOKEN);
|
|
5179
5462
|
}
|
|
5180
5463
|
}
|
|
5181
|
-
function compileToken(token, options,
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
context = (_a = options.context) !== null && _a !== void 0 ? _a : context;
|
|
5464
|
+
function compileToken(token, options, ctx) {
|
|
5465
|
+
token.forEach(sortRules);
|
|
5466
|
+
const { context = ctx, rootFunc = boolbaseExports.trueFunc } = options;
|
|
5185
5467
|
const isArrayContext = Array.isArray(context);
|
|
5186
5468
|
const finalContext = context && (Array.isArray(context) ? context : [context]);
|
|
5187
5469
|
// Check if the selector is relative
|
|
@@ -5192,12 +5474,11 @@ function compileToken(token, options, context) {
|
|
|
5192
5474
|
throw new Error("Relative selectors are not allowed when the `relativeSelector` option is disabled");
|
|
5193
5475
|
}
|
|
5194
5476
|
let shouldTestNextSiblings = false;
|
|
5195
|
-
|
|
5196
|
-
|
|
5477
|
+
let query = boolbaseExports.falseFunc;
|
|
5478
|
+
combineLoop: for (const rules of token) {
|
|
5197
5479
|
if (rules.length >= 2) {
|
|
5198
5480
|
const [first, second] = rules;
|
|
5199
|
-
if (first.type !== SelectorType.Pseudo ||
|
|
5200
|
-
first.name !== "scope") ;
|
|
5481
|
+
if (first.type !== SelectorType.Pseudo || first.name !== "scope") ;
|
|
5201
5482
|
else if (isArrayContext &&
|
|
5202
5483
|
second.type === SelectorType.Descendant) {
|
|
5203
5484
|
rules[1] = FLEXIBLE_DESCENDANT_TOKEN;
|
|
@@ -5207,28 +5488,30 @@ function compileToken(token, options, context) {
|
|
|
5207
5488
|
shouldTestNextSiblings = true;
|
|
5208
5489
|
}
|
|
5209
5490
|
}
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
|
|
5491
|
+
let next = rootFunc;
|
|
5492
|
+
let hasExpensiveSubselector = false;
|
|
5493
|
+
for (const rule of rules) {
|
|
5494
|
+
next = compileGeneralSelector(next, rule, options, finalContext, compileToken, hasExpensiveSubselector);
|
|
5495
|
+
const quality = getQuality(rule);
|
|
5496
|
+
if (quality === 0) {
|
|
5497
|
+
hasExpensiveSubselector = true;
|
|
5498
|
+
}
|
|
5499
|
+
// If the sub-selector won't match any elements, skip it.
|
|
5500
|
+
if (next === boolbaseExports.falseFunc) {
|
|
5501
|
+
continue combineLoop;
|
|
5502
|
+
}
|
|
5503
|
+
}
|
|
5504
|
+
// If we have a function that always returns true, we can stop here.
|
|
5505
|
+
if (next === rootFunc) {
|
|
5506
|
+
return rootFunc;
|
|
5507
|
+
}
|
|
5508
|
+
query = query === boolbaseExports.falseFunc ? next : or(query, next);
|
|
5509
|
+
}
|
|
5213
5510
|
query.shouldTestNextSiblings = shouldTestNextSiblings;
|
|
5214
5511
|
return query;
|
|
5215
5512
|
}
|
|
5216
|
-
function
|
|
5217
|
-
|
|
5218
|
-
return rules.reduce((previous, rule) => previous === boolbase.falseFunc
|
|
5219
|
-
? boolbase.falseFunc
|
|
5220
|
-
: compileGeneralSelector(previous, rule, options, context, compileToken), (_a = options.rootFunc) !== null && _a !== void 0 ? _a : boolbase.trueFunc);
|
|
5221
|
-
}
|
|
5222
|
-
function reduceRules(a, b) {
|
|
5223
|
-
if (b === boolbase.falseFunc || a === boolbase.trueFunc) {
|
|
5224
|
-
return a;
|
|
5225
|
-
}
|
|
5226
|
-
if (a === boolbase.falseFunc || b === boolbase.trueFunc) {
|
|
5227
|
-
return b;
|
|
5228
|
-
}
|
|
5229
|
-
return function combine(elem) {
|
|
5230
|
-
return a(elem) || b(elem);
|
|
5231
|
-
};
|
|
5513
|
+
function or(a, b) {
|
|
5514
|
+
return (elem) => a(elem) || b(elem);
|
|
5232
5515
|
}
|
|
5233
5516
|
|
|
5234
5517
|
const defaultEquals = (a, b) => a === b;
|
|
@@ -5237,23 +5520,34 @@ const defaultOptions$1 = {
|
|
|
5237
5520
|
equals: defaultEquals,
|
|
5238
5521
|
};
|
|
5239
5522
|
function convertOptionFormats(options) {
|
|
5240
|
-
var _a, _b, _c, _d;
|
|
5241
5523
|
/*
|
|
5242
5524
|
* We force one format of options to the other one.
|
|
5243
5525
|
*/
|
|
5244
5526
|
// @ts-expect-error Default options may have incompatible `Node` / `ElementNode`.
|
|
5245
|
-
const opts = options
|
|
5527
|
+
const opts = options ?? defaultOptions$1;
|
|
5246
5528
|
// @ts-expect-error Same as above.
|
|
5247
|
-
|
|
5529
|
+
opts.adapter ?? (opts.adapter = DomUtils);
|
|
5248
5530
|
// @ts-expect-error `equals` does not exist on `Options`
|
|
5249
|
-
|
|
5531
|
+
opts.equals ?? (opts.equals = opts.adapter?.equals ?? defaultEquals);
|
|
5250
5532
|
return opts;
|
|
5251
5533
|
}
|
|
5534
|
+
/**
|
|
5535
|
+
* Like `compile`, but does not add a check if elements are tags.
|
|
5536
|
+
*/
|
|
5537
|
+
function _compileUnsafe(selector, options, context) {
|
|
5538
|
+
return _compileToken(typeof selector === "string" ? parse$1(selector) : selector, options, context);
|
|
5539
|
+
}
|
|
5540
|
+
/**
|
|
5541
|
+
* @deprecated Use `_compileUnsafe` instead.
|
|
5542
|
+
*/
|
|
5543
|
+
function _compileToken(selector, options, context) {
|
|
5544
|
+
return compileToken(selector, convertOptionFormats(options), context);
|
|
5545
|
+
}
|
|
5252
5546
|
function getSelectorFunc(searchFunc) {
|
|
5253
5547
|
return function select(query, elements, options) {
|
|
5254
5548
|
const opts = convertOptionFormats(options);
|
|
5255
5549
|
if (typeof query !== "function") {
|
|
5256
|
-
query =
|
|
5550
|
+
query = _compileUnsafe(query, opts, elements);
|
|
5257
5551
|
}
|
|
5258
5552
|
const filteredElements = prepareContext(elements, opts.adapter, query.shouldTestNextSiblings);
|
|
5259
5553
|
return searchFunc(query, filteredElements, opts);
|
|
@@ -5284,16 +5578,16 @@ function appendNextSiblings(elem, adapter) {
|
|
|
5284
5578
|
/**
|
|
5285
5579
|
* @template Node The generic Node type for the DOM adapter being used.
|
|
5286
5580
|
* @template ElementNode The Node type for elements for the DOM adapter being used.
|
|
5287
|
-
* @param elems Elements to query. If it is an element, its children will be queried
|
|
5581
|
+
* @param elems Elements to query. If it is an element, its children will be queried.
|
|
5288
5582
|
* @param query can be either a CSS selector string or a compiled query function.
|
|
5289
5583
|
* @param [options] options for querying the document.
|
|
5290
5584
|
* @see compile for supported selector queries.
|
|
5291
5585
|
* @returns All matching elements.
|
|
5292
5586
|
*
|
|
5293
5587
|
*/
|
|
5294
|
-
const selectAll = getSelectorFunc((query, elems, options) => query ===
|
|
5588
|
+
const selectAll = getSelectorFunc((query, elems, options) => query === boolbaseExports.falseFunc || !elems || elems.length === 0
|
|
5295
5589
|
? []
|
|
5296
|
-
:
|
|
5590
|
+
: findAll(query, elems, options));
|
|
5297
5591
|
|
|
5298
5592
|
const comma = ','.charCodeAt(0);
|
|
5299
5593
|
const semicolon = ';'.charCodeAt(0);
|
|
@@ -9380,7 +9674,7 @@ function requirePolyfills () {
|
|
|
9380
9674
|
var backoff = 0;
|
|
9381
9675
|
fs$rename(from, to, function CB (er) {
|
|
9382
9676
|
if (er
|
|
9383
|
-
&& (er.code === "EACCES" || er.code === "EPERM")
|
|
9677
|
+
&& (er.code === "EACCES" || er.code === "EPERM" || er.code === "EBUSY")
|
|
9384
9678
|
&& Date.now() - start < 60000) {
|
|
9385
9679
|
setTimeout(function() {
|
|
9386
9680
|
fs.stat(to, function (stater, st) {
|