.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / postcss-value-parser / lib / parse.js
1 var openParentheses = "(".charCodeAt(0);
2 var closeParentheses = ")".charCodeAt(0);
3 var singleQuote = "'".charCodeAt(0);
4 var doubleQuote = '"'.charCodeAt(0);
5 var backslash = "\\".charCodeAt(0);
6 var slash = "/".charCodeAt(0);
7 var comma = ",".charCodeAt(0);
8 var colon = ":".charCodeAt(0);
9 var star = "*".charCodeAt(0);
10
11 module.exports = function(input) {
12   var tokens = [];
13   var value = input;
14
15   var next, quote, prev, token, escape, escapePos, whitespacePos;
16   var pos = 0;
17   var code = value.charCodeAt(pos);
18   var max = value.length;
19   var stack = [{ nodes: tokens }];
20   var balanced = 0;
21   var parent;
22
23   var name = "";
24   var before = "";
25   var after = "";
26
27   while (pos < max) {
28     // Whitespaces
29     if (code <= 32) {
30       next = pos;
31       do {
32         next += 1;
33         code = value.charCodeAt(next);
34       } while (code <= 32);
35       token = value.slice(pos, next);
36
37       prev = tokens[tokens.length - 1];
38       if (code === closeParentheses && balanced) {
39         after = token;
40       } else if (prev && prev.type === "div") {
41         prev.after = token;
42       } else if (
43         code === comma ||
44         code === colon ||
45         (code === slash && value.charCodeAt(next + 1) !== star)
46       ) {
47         before = token;
48       } else {
49         tokens.push({
50           type: "space",
51           sourceIndex: pos,
52           value: token
53         });
54       }
55
56       pos = next;
57
58       // Quotes
59     } else if (code === singleQuote || code === doubleQuote) {
60       next = pos;
61       quote = code === singleQuote ? "'" : '"';
62       token = {
63         type: "string",
64         sourceIndex: pos,
65         quote: quote
66       };
67       do {
68         escape = false;
69         next = value.indexOf(quote, next + 1);
70         if (~next) {
71           escapePos = next;
72           while (value.charCodeAt(escapePos - 1) === backslash) {
73             escapePos -= 1;
74             escape = !escape;
75           }
76         } else {
77           value += quote;
78           next = value.length - 1;
79           token.unclosed = true;
80         }
81       } while (escape);
82       token.value = value.slice(pos + 1, next);
83
84       tokens.push(token);
85       pos = next + 1;
86       code = value.charCodeAt(pos);
87
88       // Comments
89     } else if (code === slash && value.charCodeAt(pos + 1) === star) {
90       token = {
91         type: "comment",
92         sourceIndex: pos
93       };
94
95       next = value.indexOf("*/", pos);
96       if (next === -1) {
97         token.unclosed = true;
98         next = value.length;
99       }
100
101       token.value = value.slice(pos + 2, next);
102       tokens.push(token);
103
104       pos = next + 2;
105       code = value.charCodeAt(pos);
106
107       // Dividers
108     } else if (code === slash || code === comma || code === colon) {
109       token = value[pos];
110
111       tokens.push({
112         type: "div",
113         sourceIndex: pos - before.length,
114         value: token,
115         before: before,
116         after: ""
117       });
118       before = "";
119
120       pos += 1;
121       code = value.charCodeAt(pos);
122
123       // Open parentheses
124     } else if (openParentheses === code) {
125       // Whitespaces after open parentheses
126       next = pos;
127       do {
128         next += 1;
129         code = value.charCodeAt(next);
130       } while (code <= 32);
131       token = {
132         type: "function",
133         sourceIndex: pos - name.length,
134         value: name,
135         before: value.slice(pos + 1, next)
136       };
137       pos = next;
138
139       if (name === "url" && code !== singleQuote && code !== doubleQuote) {
140         next -= 1;
141         do {
142           escape = false;
143           next = value.indexOf(")", next + 1);
144           if (~next) {
145             escapePos = next;
146             while (value.charCodeAt(escapePos - 1) === backslash) {
147               escapePos -= 1;
148               escape = !escape;
149             }
150           } else {
151             value += ")";
152             next = value.length - 1;
153             token.unclosed = true;
154           }
155         } while (escape);
156         // Whitespaces before closed
157         whitespacePos = next;
158         do {
159           whitespacePos -= 1;
160           code = value.charCodeAt(whitespacePos);
161         } while (code <= 32);
162         if (pos !== whitespacePos + 1) {
163           token.nodes = [
164             {
165               type: "word",
166               sourceIndex: pos,
167               value: value.slice(pos, whitespacePos + 1)
168             }
169           ];
170         } else {
171           token.nodes = [];
172         }
173         if (token.unclosed && whitespacePos + 1 !== next) {
174           token.after = "";
175           token.nodes.push({
176             type: "space",
177             sourceIndex: whitespacePos + 1,
178             value: value.slice(whitespacePos + 1, next)
179           });
180         } else {
181           token.after = value.slice(whitespacePos + 1, next);
182         }
183         pos = next + 1;
184         code = value.charCodeAt(pos);
185         tokens.push(token);
186       } else {
187         balanced += 1;
188         token.after = "";
189         tokens.push(token);
190         stack.push(token);
191         tokens = token.nodes = [];
192         parent = token;
193       }
194       name = "";
195
196       // Close parentheses
197     } else if (closeParentheses === code && balanced) {
198       pos += 1;
199       code = value.charCodeAt(pos);
200
201       parent.after = after;
202       after = "";
203       balanced -= 1;
204       stack.pop();
205       parent = stack[balanced];
206       tokens = parent.nodes;
207
208       // Words
209     } else {
210       next = pos;
211       do {
212         if (code === backslash) {
213           next += 1;
214         }
215         next += 1;
216         code = value.charCodeAt(next);
217       } while (
218         next < max &&
219         !(
220           code <= 32 ||
221           code === singleQuote ||
222           code === doubleQuote ||
223           code === comma ||
224           code === colon ||
225           code === slash ||
226           code === openParentheses ||
227           (code === closeParentheses && balanced)
228         )
229       );
230       token = value.slice(pos, next);
231
232       if (openParentheses === code) {
233         name = token;
234       } else {
235         tokens.push({
236           type: "word",
237           sourceIndex: pos,
238           value: token
239         });
240       }
241
242       pos = next;
243     }
244   }
245
246   for (pos = stack.length - 1; pos; pos -= 1) {
247     stack[pos].unclosed = true;
248   }
249
250   return stack[0].nodes;
251 };