source: node_modules/postcss-value-parser/lib/parse.js@ 2058e5c

Last change on this file since 2058e5c was 2058e5c, checked in by istevanoska <ilinastevanoska@…>, 6 months ago

Working / before login

  • Property mode set to 100644
File size: 8.1 KB
Line 
1var openParentheses = "(".charCodeAt(0);
2var closeParentheses = ")".charCodeAt(0);
3var singleQuote = "'".charCodeAt(0);
4var doubleQuote = '"'.charCodeAt(0);
5var backslash = "\\".charCodeAt(0);
6var slash = "/".charCodeAt(0);
7var comma = ",".charCodeAt(0);
8var colon = ":".charCodeAt(0);
9var star = "*".charCodeAt(0);
10var uLower = "u".charCodeAt(0);
11var uUpper = "U".charCodeAt(0);
12var plus = "+".charCodeAt(0);
13var isUnicodeRange = /^[a-f0-9?-]+$/i;
14
15module.exports = function(input) {
16 var tokens = [];
17 var value = input;
18
19 var next,
20 quote,
21 prev,
22 token,
23 escape,
24 escapePos,
25 whitespacePos,
26 parenthesesOpenPos;
27 var pos = 0;
28 var code = value.charCodeAt(pos);
29 var max = value.length;
30 var stack = [{ nodes: tokens }];
31 var balanced = 0;
32 var parent;
33
34 var name = "";
35 var before = "";
36 var after = "";
37
38 while (pos < max) {
39 // Whitespaces
40 if (code <= 32) {
41 next = pos;
42 do {
43 next += 1;
44 code = value.charCodeAt(next);
45 } while (code <= 32);
46 token = value.slice(pos, next);
47
48 prev = tokens[tokens.length - 1];
49 if (code === closeParentheses && balanced) {
50 after = token;
51 } else if (prev && prev.type === "div") {
52 prev.after = token;
53 prev.sourceEndIndex += token.length;
54 } else if (
55 code === comma ||
56 code === colon ||
57 (code === slash &&
58 value.charCodeAt(next + 1) !== star &&
59 (!parent ||
60 (parent && parent.type === "function" && parent.value !== "calc")))
61 ) {
62 before = token;
63 } else {
64 tokens.push({
65 type: "space",
66 sourceIndex: pos,
67 sourceEndIndex: next,
68 value: token
69 });
70 }
71
72 pos = next;
73
74 // Quotes
75 } else if (code === singleQuote || code === doubleQuote) {
76 next = pos;
77 quote = code === singleQuote ? "'" : '"';
78 token = {
79 type: "string",
80 sourceIndex: pos,
81 quote: quote
82 };
83 do {
84 escape = false;
85 next = value.indexOf(quote, next + 1);
86 if (~next) {
87 escapePos = next;
88 while (value.charCodeAt(escapePos - 1) === backslash) {
89 escapePos -= 1;
90 escape = !escape;
91 }
92 } else {
93 value += quote;
94 next = value.length - 1;
95 token.unclosed = true;
96 }
97 } while (escape);
98 token.value = value.slice(pos + 1, next);
99 token.sourceEndIndex = token.unclosed ? next : next + 1;
100 tokens.push(token);
101 pos = next + 1;
102 code = value.charCodeAt(pos);
103
104 // Comments
105 } else if (code === slash && value.charCodeAt(pos + 1) === star) {
106 next = value.indexOf("*/", pos);
107
108 token = {
109 type: "comment",
110 sourceIndex: pos,
111 sourceEndIndex: next + 2
112 };
113
114 if (next === -1) {
115 token.unclosed = true;
116 next = value.length;
117 token.sourceEndIndex = next;
118 }
119
120 token.value = value.slice(pos + 2, next);
121 tokens.push(token);
122
123 pos = next + 2;
124 code = value.charCodeAt(pos);
125
126 // Operation within calc
127 } else if (
128 (code === slash || code === star) &&
129 parent &&
130 parent.type === "function" &&
131 parent.value === "calc"
132 ) {
133 token = value[pos];
134 tokens.push({
135 type: "word",
136 sourceIndex: pos - before.length,
137 sourceEndIndex: pos + token.length,
138 value: token
139 });
140 pos += 1;
141 code = value.charCodeAt(pos);
142
143 // Dividers
144 } else if (code === slash || code === comma || code === colon) {
145 token = value[pos];
146
147 tokens.push({
148 type: "div",
149 sourceIndex: pos - before.length,
150 sourceEndIndex: pos + token.length,
151 value: token,
152 before: before,
153 after: ""
154 });
155 before = "";
156
157 pos += 1;
158 code = value.charCodeAt(pos);
159
160 // Open parentheses
161 } else if (openParentheses === code) {
162 // Whitespaces after open parentheses
163 next = pos;
164 do {
165 next += 1;
166 code = value.charCodeAt(next);
167 } while (code <= 32);
168 parenthesesOpenPos = pos;
169 token = {
170 type: "function",
171 sourceIndex: pos - name.length,
172 value: name,
173 before: value.slice(parenthesesOpenPos + 1, next)
174 };
175 pos = next;
176
177 if (name === "url" && code !== singleQuote && code !== doubleQuote) {
178 next -= 1;
179 do {
180 escape = false;
181 next = value.indexOf(")", next + 1);
182 if (~next) {
183 escapePos = next;
184 while (value.charCodeAt(escapePos - 1) === backslash) {
185 escapePos -= 1;
186 escape = !escape;
187 }
188 } else {
189 value += ")";
190 next = value.length - 1;
191 token.unclosed = true;
192 }
193 } while (escape);
194 // Whitespaces before closed
195 whitespacePos = next;
196 do {
197 whitespacePos -= 1;
198 code = value.charCodeAt(whitespacePos);
199 } while (code <= 32);
200 if (parenthesesOpenPos < whitespacePos) {
201 if (pos !== whitespacePos + 1) {
202 token.nodes = [
203 {
204 type: "word",
205 sourceIndex: pos,
206 sourceEndIndex: whitespacePos + 1,
207 value: value.slice(pos, whitespacePos + 1)
208 }
209 ];
210 } else {
211 token.nodes = [];
212 }
213 if (token.unclosed && whitespacePos + 1 !== next) {
214 token.after = "";
215 token.nodes.push({
216 type: "space",
217 sourceIndex: whitespacePos + 1,
218 sourceEndIndex: next,
219 value: value.slice(whitespacePos + 1, next)
220 });
221 } else {
222 token.after = value.slice(whitespacePos + 1, next);
223 token.sourceEndIndex = next;
224 }
225 } else {
226 token.after = "";
227 token.nodes = [];
228 }
229 pos = next + 1;
230 token.sourceEndIndex = token.unclosed ? next : pos;
231 code = value.charCodeAt(pos);
232 tokens.push(token);
233 } else {
234 balanced += 1;
235 token.after = "";
236 token.sourceEndIndex = pos + 1;
237 tokens.push(token);
238 stack.push(token);
239 tokens = token.nodes = [];
240 parent = token;
241 }
242 name = "";
243
244 // Close parentheses
245 } else if (closeParentheses === code && balanced) {
246 pos += 1;
247 code = value.charCodeAt(pos);
248
249 parent.after = after;
250 parent.sourceEndIndex += after.length;
251 after = "";
252 balanced -= 1;
253 stack[stack.length - 1].sourceEndIndex = pos;
254 stack.pop();
255 parent = stack[balanced];
256 tokens = parent.nodes;
257
258 // Words
259 } else {
260 next = pos;
261 do {
262 if (code === backslash) {
263 next += 1;
264 }
265 next += 1;
266 code = value.charCodeAt(next);
267 } while (
268 next < max &&
269 !(
270 code <= 32 ||
271 code === singleQuote ||
272 code === doubleQuote ||
273 code === comma ||
274 code === colon ||
275 code === slash ||
276 code === openParentheses ||
277 (code === star &&
278 parent &&
279 parent.type === "function" &&
280 parent.value === "calc") ||
281 (code === slash &&
282 parent.type === "function" &&
283 parent.value === "calc") ||
284 (code === closeParentheses && balanced)
285 )
286 );
287 token = value.slice(pos, next);
288
289 if (openParentheses === code) {
290 name = token;
291 } else if (
292 (uLower === token.charCodeAt(0) || uUpper === token.charCodeAt(0)) &&
293 plus === token.charCodeAt(1) &&
294 isUnicodeRange.test(token.slice(2))
295 ) {
296 tokens.push({
297 type: "unicode-range",
298 sourceIndex: pos,
299 sourceEndIndex: next,
300 value: token
301 });
302 } else {
303 tokens.push({
304 type: "word",
305 sourceIndex: pos,
306 sourceEndIndex: next,
307 value: token
308 });
309 }
310
311 pos = next;
312 }
313 }
314
315 for (pos = stack.length - 1; pos; pos -= 1) {
316 stack[pos].unclosed = true;
317 stack[pos].sourceEndIndex = value.length;
318 }
319
320 return stack[0].nodes;
321};
Note: See TracBrowser for help on using the repository browser.