UNPKG

11.1 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3var utils_1 = require("./utils");
4function parseCssSelector(str, pos, pseudos, attrEqualityMods, ruleNestingOperators, substitutesEnabled) {
5 var l = str.length;
6 var chr = '';
7 function getStr(quote, escapeTable) {
8 var result = '';
9 pos++;
10 chr = str.charAt(pos);
11 while (pos < l) {
12 if (chr === quote) {
13 pos++;
14 return result;
15 }
16 else if (chr === '\\') {
17 pos++;
18 chr = str.charAt(pos);
19 var esc = void 0;
20 if (chr === quote) {
21 result += quote;
22 }
23 else if ((esc = escapeTable[chr]) !== undefined) {
24 result += esc;
25 }
26 else if (utils_1.isHex(chr)) {
27 var hex = chr;
28 pos++;
29 chr = str.charAt(pos);
30 while (utils_1.isHex(chr)) {
31 hex += chr;
32 pos++;
33 chr = str.charAt(pos);
34 }
35 if (chr === ' ') {
36 pos++;
37 chr = str.charAt(pos);
38 }
39 result += String.fromCharCode(parseInt(hex, 16));
40 continue;
41 }
42 else {
43 result += chr;
44 }
45 }
46 else {
47 result += chr;
48 }
49 pos++;
50 chr = str.charAt(pos);
51 }
52 return result;
53 }
54 function getIdent() {
55 var result = '';
56 chr = str.charAt(pos);
57 while (pos < l) {
58 if (utils_1.isIdent(chr)) {
59 result += chr;
60 }
61 else if (chr === '\\') {
62 pos++;
63 if (pos >= l) {
64 throw Error('Expected symbol but end of file reached.');
65 }
66 chr = str.charAt(pos);
67 if (utils_1.identSpecialChars[chr]) {
68 result += chr;
69 }
70 else if (utils_1.isHex(chr)) {
71 var hex = chr;
72 pos++;
73 chr = str.charAt(pos);
74 while (utils_1.isHex(chr)) {
75 hex += chr;
76 pos++;
77 chr = str.charAt(pos);
78 }
79 if (chr === ' ') {
80 pos++;
81 chr = str.charAt(pos);
82 }
83 result += String.fromCharCode(parseInt(hex, 16));
84 continue;
85 }
86 else {
87 result += chr;
88 }
89 }
90 else {
91 return result;
92 }
93 pos++;
94 chr = str.charAt(pos);
95 }
96 return result;
97 }
98 function skipWhitespace() {
99 chr = str.charAt(pos);
100 var result = false;
101 while (chr === ' ' || chr === "\t" || chr === "\n" || chr === "\r" || chr === "\f") {
102 result = true;
103 pos++;
104 chr = str.charAt(pos);
105 }
106 return result;
107 }
108 function parse() {
109 var res = parseSelector();
110 if (pos < l) {
111 throw Error('Rule expected but "' + str.charAt(pos) + '" found.');
112 }
113 return res;
114 }
115 function parseSelector() {
116 var selector = parseSingleSelector();
117 if (!selector) {
118 return null;
119 }
120 var res = selector;
121 chr = str.charAt(pos);
122 while (chr === ',') {
123 pos++;
124 skipWhitespace();
125 if (res.type !== 'selectors') {
126 res = {
127 type: 'selectors',
128 selectors: [selector]
129 };
130 }
131 selector = parseSingleSelector();
132 if (!selector) {
133 throw Error('Rule expected after ",".');
134 }
135 res.selectors.push(selector);
136 }
137 return res;
138 }
139 function parseSingleSelector() {
140 skipWhitespace();
141 var selector = {
142 type: 'ruleSet'
143 };
144 var rule = parseRule();
145 if (!rule) {
146 return null;
147 }
148 var currentRule = selector;
149 while (rule) {
150 rule.type = 'rule';
151 currentRule.rule = rule;
152 currentRule = rule;
153 skipWhitespace();
154 chr = str.charAt(pos);
155 if (pos >= l || chr === ',' || chr === ')') {
156 break;
157 }
158 if (ruleNestingOperators[chr]) {
159 var op = chr;
160 pos++;
161 skipWhitespace();
162 rule = parseRule();
163 if (!rule) {
164 throw Error('Rule expected after "' + op + '".');
165 }
166 rule.nestingOperator = op;
167 }
168 else {
169 rule = parseRule();
170 if (rule) {
171 rule.nestingOperator = null;
172 }
173 }
174 }
175 return selector;
176 }
177 // @ts-ignore no-overlap
178 function parseRule() {
179 var rule = null;
180 while (pos < l) {
181 chr = str.charAt(pos);
182 if (chr === '*') {
183 pos++;
184 (rule = rule || {}).tagName = '*';
185 }
186 else if (utils_1.isIdentStart(chr) || chr === '\\') {
187 (rule = rule || {}).tagName = getIdent();
188 }
189 else if (chr === '.') {
190 pos++;
191 rule = rule || {};
192 (rule.classNames = rule.classNames || []).push(getIdent());
193 }
194 else if (chr === '#') {
195 pos++;
196 (rule = rule || {}).id = getIdent();
197 }
198 else if (chr === '[') {
199 pos++;
200 skipWhitespace();
201 var attr = {
202 name: getIdent()
203 };
204 skipWhitespace();
205 // @ts-ignore
206 if (chr === ']') {
207 pos++;
208 }
209 else {
210 var operator = '';
211 if (attrEqualityMods[chr]) {
212 operator = chr;
213 pos++;
214 chr = str.charAt(pos);
215 }
216 if (pos >= l) {
217 throw Error('Expected "=" but end of file reached.');
218 }
219 if (chr !== '=') {
220 throw Error('Expected "=" but "' + chr + '" found.');
221 }
222 attr.operator = operator + '=';
223 pos++;
224 skipWhitespace();
225 var attrValue = '';
226 attr.valueType = 'string';
227 // @ts-ignore
228 if (chr === '"') {
229 attrValue = getStr('"', utils_1.doubleQuotesEscapeChars);
230 // @ts-ignore
231 }
232 else if (chr === '\'') {
233 attrValue = getStr('\'', utils_1.singleQuoteEscapeChars);
234 // @ts-ignore
235 }
236 else if (substitutesEnabled && chr === '$') {
237 pos++;
238 attrValue = getIdent();
239 attr.valueType = 'substitute';
240 }
241 else {
242 while (pos < l) {
243 if (chr === ']') {
244 break;
245 }
246 attrValue += chr;
247 pos++;
248 chr = str.charAt(pos);
249 }
250 attrValue = attrValue.trim();
251 }
252 skipWhitespace();
253 if (pos >= l) {
254 throw Error('Expected "]" but end of file reached.');
255 }
256 if (chr !== ']') {
257 throw Error('Expected "]" but "' + chr + '" found.');
258 }
259 pos++;
260 attr.value = attrValue;
261 }
262 rule = rule || {};
263 (rule.attrs = rule.attrs || []).push(attr);
264 }
265 else if (chr === ':') {
266 pos++;
267 var pseudoName = getIdent();
268 var pseudo = {
269 name: pseudoName
270 };
271 // @ts-ignore
272 if (chr === '(') {
273 pos++;
274 var value = '';
275 skipWhitespace();
276 if (pseudos[pseudoName] === 'selector') {
277 pseudo.valueType = 'selector';
278 value = parseSelector();
279 }
280 else {
281 pseudo.valueType = pseudos[pseudoName] || 'string';
282 // @ts-ignore
283 if (chr === '"') {
284 value = getStr('"', utils_1.doubleQuotesEscapeChars);
285 // @ts-ignore
286 }
287 else if (chr === '\'') {
288 value = getStr('\'', utils_1.singleQuoteEscapeChars);
289 // @ts-ignore
290 }
291 else if (substitutesEnabled && chr === '$') {
292 pos++;
293 value = getIdent();
294 pseudo.valueType = 'substitute';
295 }
296 else {
297 while (pos < l) {
298 if (chr === ')') {
299 break;
300 }
301 value += chr;
302 pos++;
303 chr = str.charAt(pos);
304 }
305 value = value.trim();
306 }
307 skipWhitespace();
308 }
309 if (pos >= l) {
310 throw Error('Expected ")" but end of file reached.');
311 }
312 if (chr !== ')') {
313 throw Error('Expected ")" but "' + chr + '" found.');
314 }
315 pos++;
316 pseudo.value = value;
317 }
318 rule = rule || {};
319 (rule.pseudos = rule.pseudos || []).push(pseudo);
320 }
321 else {
322 break;
323 }
324 }
325 return rule;
326 }
327 return parse();
328}
329exports.parseCssSelector = parseCssSelector;