blob: abe4471777ae1eaf4f45f8a17579ac2e7c51e11e [file] [log] [blame]
Leo Repp58b9f112021-11-22 11:57:47 +01001"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.default = parse;
4var reName = /^[^\\]?(?:\\(?:[\da-f]{1,6}\s?|.)|[\w\-\u00b0-\uFFFF])+/;
5var reEscape = /\\([\da-f]{1,6}\s?|(\s)|.)/gi;
6// Modified version of https://github.com/jquery/sizzle/blob/master/src/sizzle.js#L87
7var reAttr = /^\s*((?:\\.|[\w\u00b0-\uFFFF-])+)\s*(?:(\S?)=\s*(?:(['"])((?:[^\\]|\\[^])*?)\3|(#?(?:\\.|[\w\u00b0-\uFFFF-])*)|)|)\s*(i)?\]/;
8var actionTypes = {
9 undefined: "exists",
10 "": "equals",
11 "~": "element",
12 "^": "start",
13 $: "end",
14 "*": "any",
15 "!": "not",
16 "|": "hyphen",
17};
18var Traversals = {
19 ">": "child",
20 "<": "parent",
21 "~": "sibling",
22 "+": "adjacent",
23};
24var attribSelectors = {
25 "#": ["id", "equals"],
26 ".": ["class", "element"],
27};
28// Pseudos, whose data property is parsed as well.
29var unpackPseudos = new Set([
30 "has",
31 "not",
32 "matches",
33 "is",
34 "host",
35 "host-context",
36]);
37var stripQuotesFromPseudos = new Set(["contains", "icontains"]);
38var quotes = new Set(['"', "'"]);
39// Unescape function taken from https://github.com/jquery/sizzle/blob/master/src/sizzle.js#L152
40function funescape(_, escaped, escapedWhitespace) {
41 var high = parseInt(escaped, 16) - 0x10000;
42 // NaN means non-codepoint
43 return high !== high || escapedWhitespace
44 ? escaped
45 : high < 0
46 ? // BMP codepoint
47 String.fromCharCode(high + 0x10000)
48 : // Supplemental Plane codepoint (surrogate pair)
49 String.fromCharCode((high >> 10) | 0xd800, (high & 0x3ff) | 0xdc00);
50}
51function unescapeCSS(str) {
52 return str.replace(reEscape, funescape);
53}
54function isWhitespace(c) {
55 return c === " " || c === "\n" || c === "\t" || c === "\f" || c === "\r";
56}
57function parse(selector, options) {
58 var subselects = [];
59 selector = parseSelector(subselects, "" + selector, options);
60 if (selector !== "") {
61 throw new Error("Unmatched selector: " + selector);
62 }
63 return subselects;
64}
65function parseSelector(subselects, selector, options) {
66 var _a, _b;
67 if (options === void 0) { options = {}; }
68 var tokens = [];
69 var sawWS = false;
70 function getName() {
71 var match = selector.match(reName);
72 if (!match) {
73 throw new Error("Expected name, found " + selector);
74 }
75 var sub = match[0];
76 selector = selector.substr(sub.length);
77 return unescapeCSS(sub);
78 }
79 function stripWhitespace(start) {
80 while (isWhitespace(selector.charAt(start)))
81 start++;
82 selector = selector.substr(start);
83 }
84 function isEscaped(pos) {
85 var slashCount = 0;
86 while (selector.charAt(--pos) === "\\")
87 slashCount++;
88 return (slashCount & 1) === 1;
89 }
90 stripWhitespace(0);
91 while (selector !== "") {
92 var firstChar = selector.charAt(0);
93 if (isWhitespace(firstChar)) {
94 sawWS = true;
95 stripWhitespace(1);
96 }
97 else if (firstChar in Traversals) {
98 tokens.push({ type: Traversals[firstChar] });
99 sawWS = false;
100 stripWhitespace(1);
101 }
102 else if (firstChar === ",") {
103 if (tokens.length === 0) {
104 throw new Error("Empty sub-selector");
105 }
106 subselects.push(tokens);
107 tokens = [];
108 sawWS = false;
109 stripWhitespace(1);
110 }
111 else {
112 if (sawWS) {
113 if (tokens.length > 0) {
114 tokens.push({ type: "descendant" });
115 }
116 sawWS = false;
117 }
118 if (firstChar === "*") {
119 selector = selector.substr(1);
120 tokens.push({ type: "universal" });
121 }
122 else if (firstChar in attribSelectors) {
123 var _c = attribSelectors[firstChar], name_1 = _c[0], action = _c[1];
124 selector = selector.substr(1);
125 tokens.push({
126 type: "attribute",
127 name: name_1,
128 action: action,
129 value: getName(),
130 ignoreCase: false,
131 });
132 }
133 else if (firstChar === "[") {
134 selector = selector.substr(1);
135 var attributeMatch = selector.match(reAttr);
136 if (!attributeMatch) {
137 throw new Error("Malformed attribute selector: " + selector);
138 }
139 var completeSelector = attributeMatch[0], baseName = attributeMatch[1], actionType = attributeMatch[2], _d = attributeMatch[4], quotedValue = _d === void 0 ? "" : _d, _e = attributeMatch[5], value = _e === void 0 ? quotedValue : _e, ignoreCase = attributeMatch[6];
140 selector = selector.substr(completeSelector.length);
141 var name_2 = unescapeCSS(baseName);
142 if ((_a = options.lowerCaseAttributeNames) !== null && _a !== void 0 ? _a : !options.xmlMode) {
143 name_2 = name_2.toLowerCase();
144 }
145 tokens.push({
146 type: "attribute",
147 name: name_2,
148 action: actionTypes[actionType],
149 value: unescapeCSS(value),
150 ignoreCase: !!ignoreCase,
151 });
152 }
153 else if (firstChar === ":") {
154 if (selector.charAt(1) === ":") {
155 selector = selector.substr(2);
156 tokens.push({
157 type: "pseudo-element",
158 name: getName().toLowerCase(),
159 });
160 continue;
161 }
162 selector = selector.substr(1);
163 var name_3 = getName().toLowerCase();
164 var data = null;
165 if (selector.startsWith("(")) {
166 if (unpackPseudos.has(name_3)) {
167 var quot = selector.charAt(1);
168 var quoted = quotes.has(quot);
169 selector = selector.substr(quoted ? 2 : 1);
170 data = [];
171 selector = parseSelector(data, selector, options);
172 if (quoted) {
173 if (!selector.startsWith(quot)) {
174 throw new Error("Unmatched quotes in :" + name_3);
175 }
176 else {
177 selector = selector.substr(1);
178 }
179 }
180 if (!selector.startsWith(")")) {
181 throw new Error("Missing closing parenthesis in :" + name_3 + " (" + selector + ")");
182 }
183 selector = selector.substr(1);
184 }
185 else {
186 var pos = 1;
187 var counter = 1;
188 for (; counter > 0 && pos < selector.length; pos++) {
189 if (selector.charAt(pos) === "(" &&
190 !isEscaped(pos)) {
191 counter++;
192 }
193 else if (selector.charAt(pos) === ")" &&
194 !isEscaped(pos)) {
195 counter--;
196 }
197 }
198 if (counter) {
199 throw new Error("Parenthesis not matched");
200 }
201 data = selector.substr(1, pos - 2);
202 selector = selector.substr(pos);
203 if (stripQuotesFromPseudos.has(name_3)) {
204 var quot = data.charAt(0);
205 if (quot === data.slice(-1) && quotes.has(quot)) {
206 data = data.slice(1, -1);
207 }
208 data = unescapeCSS(data);
209 }
210 }
211 }
212 tokens.push({ type: "pseudo", name: name_3, data: data });
213 }
214 else if (reName.test(selector)) {
215 var name_4 = getName();
216 if ((_b = options.lowerCaseTags) !== null && _b !== void 0 ? _b : !options.xmlMode) {
217 name_4 = name_4.toLowerCase();
218 }
219 tokens.push({ type: "tag", name: name_4 });
220 }
221 else {
222 if (tokens.length &&
223 tokens[tokens.length - 1].type === "descendant") {
224 tokens.pop();
225 }
226 addToken(subselects, tokens);
227 return selector;
228 }
229 }
230 }
231 addToken(subselects, tokens);
232 return selector;
233}
234function addToken(subselects, tokens) {
235 if (subselects.length > 0 && tokens.length === 0) {
236 throw new Error("Empty sub-selector");
237 }
238 subselects.push(tokens);
239}