source: trip-planner-front/node_modules/postcss-values-parser/lib/tokenize.js

Last change on this file was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 10.0 KB
Line 
1'use strict';
2
3const openBracket = '{'.charCodeAt(0);
4const closeBracket = '}'.charCodeAt(0);
5const openParen = '('.charCodeAt(0);
6const closeParen = ')'.charCodeAt(0);
7const singleQuote = '\''.charCodeAt(0);
8const doubleQuote = '"'.charCodeAt(0);
9const backslash = '\\'.charCodeAt(0);
10const slash = '/'.charCodeAt(0);
11const period = '.'.charCodeAt(0);
12const comma = ','.charCodeAt(0);
13const colon = ':'.charCodeAt(0);
14const asterisk = '*'.charCodeAt(0);
15const minus = '-'.charCodeAt(0);
16const plus = '+'.charCodeAt(0);
17const pound = '#'.charCodeAt(0);
18const newline = '\n'.charCodeAt(0);
19const space = ' '.charCodeAt(0);
20const feed = '\f'.charCodeAt(0);
21const tab = '\t'.charCodeAt(0);
22const cr = '\r'.charCodeAt(0);
23const at = '@'.charCodeAt(0);
24const lowerE = 'e'.charCodeAt(0);
25const upperE = 'E'.charCodeAt(0);
26const digit0 = '0'.charCodeAt(0);
27const digit9 = '9'.charCodeAt(0);
28const lowerU = 'u'.charCodeAt(0);
29const upperU = 'U'.charCodeAt(0);
30const atEnd = /[ \n\t\r\{\(\)'"\\;,/]/g;
31const wordEnd = /[ \n\t\r\(\)\{\}\*:;@!&'"\+\|~>,\[\]\\]|\/(?=\*)/g;
32const wordEndNum = /[ \n\t\r\(\)\{\}\*:;@!&'"\-\+\|~>,\[\]\\]|\//g;
33const alphaNum = /^[a-z0-9]/i;
34const unicodeRange = /^[a-f0-9?\-]/i;
35
36const util = require('util');
37const TokenizeError = require('./errors/TokenizeError');
38
39module.exports = function tokenize (input, options) {
40
41 options = options || {};
42
43 let tokens = [],
44 css = input.valueOf(),
45 length = css.length,
46 offset = -1,
47 line = 1,
48 pos = 0,
49 parentCount = 0,
50 isURLArg = null,
51
52 code, next, quote, lines, last, content, escape, nextLine, nextOffset,
53 escaped, escapePos, nextChar;
54
55 function unclosed (what) {
56 let message = util.format('Unclosed %s at line: %d, column: %d, token: %d', what, line, pos - offset, pos);
57 throw new TokenizeError(message);
58 }
59
60 function tokenizeError () {
61 let message = util.format('Syntax error at line: %d, column: %d, token: %d', line, pos - offset, pos);
62 throw new TokenizeError(message);
63 }
64
65 while (pos < length) {
66 code = css.charCodeAt(pos);
67
68 if (code === newline) {
69 offset = pos;
70 line += 1;
71 }
72
73 switch (code) {
74 case newline:
75 case space:
76 case tab:
77 case cr:
78 case feed:
79 next = pos;
80 do {
81 next += 1;
82 code = css.charCodeAt(next);
83 if (code === newline) {
84 offset = next;
85 line += 1;
86 }
87 } while (code === space ||
88 code === newline ||
89 code === tab ||
90 code === cr ||
91 code === feed);
92
93 tokens.push(['space', css.slice(pos, next),
94 line, pos - offset,
95 line, next - offset,
96 pos
97 ]);
98
99 pos = next - 1;
100 break;
101
102 case colon:
103 next = pos + 1;
104 tokens.push(['colon', css.slice(pos, next),
105 line, pos - offset,
106 line, next - offset,
107 pos
108 ]);
109
110 pos = next - 1;
111 break;
112
113 case comma:
114 next = pos + 1;
115 tokens.push(['comma', css.slice(pos, next),
116 line, pos - offset,
117 line, next - offset,
118 pos
119 ]);
120
121 pos = next - 1;
122 break;
123
124 case openBracket:
125 tokens.push(['{', '{',
126 line, pos - offset,
127 line, next - offset,
128 pos
129 ]);
130 break;
131
132 case closeBracket:
133 tokens.push(['}', '}',
134 line, pos - offset,
135 line, next - offset,
136 pos
137 ]);
138 break;
139
140 case openParen:
141 parentCount++;
142 isURLArg = !isURLArg && parentCount === 1 &&
143 tokens.length > 0 &&
144 tokens[tokens.length - 1][0] === "word" &&
145 tokens[tokens.length - 1][1] === "url";
146 tokens.push(['(', '(',
147 line, pos - offset,
148 line, next - offset,
149 pos
150 ]);
151 break;
152
153 case closeParen:
154 parentCount--;
155 isURLArg = isURLArg && parentCount > 0;
156 tokens.push([')', ')',
157 line, pos - offset,
158 line, next - offset,
159 pos
160 ]);
161 break;
162
163 case singleQuote:
164 case doubleQuote:
165 quote = code === singleQuote ? '\'' : '"';
166 next = pos;
167 do {
168 escaped = false;
169 next = css.indexOf(quote, next + 1);
170 if (next === -1) {
171 unclosed('quote', quote);
172 }
173 escapePos = next;
174 while (css.charCodeAt(escapePos - 1) === backslash) {
175 escapePos -= 1;
176 escaped = !escaped;
177 }
178 } while (escaped);
179
180 tokens.push(['string', css.slice(pos, next + 1),
181 line, pos - offset,
182 line, next - offset,
183 pos
184 ]);
185 pos = next;
186 break;
187
188 case at:
189 atEnd.lastIndex = pos + 1;
190 atEnd.test(css);
191
192 if (atEnd.lastIndex === 0) {
193 next = css.length - 1;
194 }
195 else {
196 next = atEnd.lastIndex - 2;
197 }
198
199 tokens.push(['atword', css.slice(pos, next + 1),
200 line, pos - offset,
201 line, next - offset,
202 pos
203 ]);
204 pos = next;
205 break;
206
207 case backslash:
208 next = pos;
209 code = css.charCodeAt(next + 1);
210
211 if (escape && (code !== slash && code !== space &&
212 code !== newline && code !== tab &&
213 code !== cr && code !== feed)) {
214 next += 1;
215 }
216
217 tokens.push(['word', css.slice(pos, next + 1),
218 line, pos - offset,
219 line, next - offset,
220 pos
221 ]);
222
223 pos = next;
224 break;
225
226 case plus:
227 case minus:
228 case asterisk:
229 next = pos + 1;
230 nextChar = css.slice(pos + 1, next + 1);
231
232 let prevChar = css.slice(pos - 1, pos);
233
234 // if the operator is immediately followed by a word character, then we
235 // have a prefix of some kind, and should fall-through. eg. -webkit
236
237 // look for --* for custom variables
238 if (code === minus && nextChar.charCodeAt(0) === minus) {
239 next++;
240
241 tokens.push(['word', css.slice(pos, next),
242 line, pos - offset,
243 line, next - offset,
244 pos
245 ]);
246
247 pos = next - 1;
248 break;
249 }
250
251 tokens.push(['operator', css.slice(pos, next),
252 line, pos - offset,
253 line, next - offset,
254 pos
255 ]);
256
257 pos = next - 1;
258 break;
259
260 default:
261 if (code === slash && (css.charCodeAt(pos + 1) === asterisk || (options.loose && !isURLArg && css.charCodeAt(pos + 1) === slash))) {
262 const isStandardComment = css.charCodeAt(pos + 1) === asterisk;
263
264 if (isStandardComment) {
265 next = css.indexOf('*/', pos + 2) + 1;
266 if (next === 0) {
267 unclosed('comment', '*/');
268 }
269 }
270 else {
271 const newlinePos = css.indexOf('\n', pos + 2);
272
273 next = newlinePos !== -1 ? newlinePos - 1 : length;
274 }
275
276 content = css.slice(pos, next + 1);
277 lines = content.split('\n');
278 last = lines.length - 1;
279
280 if (last > 0) {
281 nextLine = line + last;
282 nextOffset = next - lines[last].length;
283 }
284 else {
285 nextLine = line;
286 nextOffset = offset;
287 }
288
289 tokens.push(['comment', content,
290 line, pos - offset,
291 nextLine, next - nextOffset,
292 pos
293 ]);
294
295 offset = nextOffset;
296 line = nextLine;
297 pos = next;
298
299 }
300 else if (code === pound && !alphaNum.test(css.slice(pos + 1, pos + 2))) {
301 next = pos + 1;
302
303 tokens.push(['#', css.slice(pos, next),
304 line, pos - offset,
305 line, next - offset,
306 pos
307 ]);
308
309 pos = next - 1;
310 }
311 else if ((code === lowerU || code === upperU) && css.charCodeAt(pos + 1) === plus) {
312 next = pos + 2;
313
314 do {
315 next += 1;
316 code = css.charCodeAt(next);
317 } while (next < length && unicodeRange.test(css.slice(next, next + 1)));
318
319 tokens.push(['unicoderange', css.slice(pos, next),
320 line, pos - offset,
321 line, next - offset,
322 pos
323 ]);
324 pos = next - 1;
325 }
326 // catch a regular slash, that isn't a comment
327 else if (code === slash) {
328 next = pos + 1;
329
330 tokens.push(['operator', css.slice(pos, next),
331 line, pos - offset,
332 line, next - offset,
333 pos
334 ]);
335
336 pos = next - 1;
337 }
338 else {
339 let regex = wordEnd;
340
341 // we're dealing with a word that starts with a number
342 // those get treated differently
343 if (code >= digit0 && code <= digit9) {
344 regex = wordEndNum;
345 }
346
347 regex.lastIndex = pos + 1;
348 regex.test(css);
349
350 if (regex.lastIndex === 0) {
351 next = css.length - 1;
352 }
353 else {
354 next = regex.lastIndex - 2;
355 }
356
357 // Exponential number notation with minus or plus: 1e-10, 1e+10
358 if (regex === wordEndNum || code === period) {
359 let ncode = css.charCodeAt(next),
360 ncode1 = css.charCodeAt(next + 1),
361 ncode2 = css.charCodeAt(next + 2);
362
363 if (
364 (ncode === lowerE || ncode === upperE) &&
365 (ncode1 === minus || ncode1 === plus) &&
366 (ncode2 >= digit0 && ncode2 <= digit9)
367 ) {
368 wordEndNum.lastIndex = next + 2;
369 wordEndNum.test(css);
370
371 if (wordEndNum.lastIndex === 0) {
372 next = css.length - 1;
373 }
374 else {
375 next = wordEndNum.lastIndex - 2;
376 }
377 }
378 }
379
380 tokens.push(['word', css.slice(pos, next + 1),
381 line, pos - offset,
382 line, next - offset,
383 pos
384 ]);
385 pos = next;
386 }
387 break;
388 }
389
390 pos ++;
391 }
392
393 return tokens;
394};
Note: See TracBrowser for help on using the repository browser.