.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / postcss-media-query-parser / dist / parsers.js
1 'use strict';
2
3 Object.defineProperty(exports, "__esModule", {
4   value: true
5 });
6 exports.parseMediaFeature = parseMediaFeature;
7 exports.parseMediaQuery = parseMediaQuery;
8 exports.parseMediaList = parseMediaList;
9
10 var _Node = require('./nodes/Node');
11
12 var _Node2 = _interopRequireDefault(_Node);
13
14 var _Container = require('./nodes/Container');
15
16 var _Container2 = _interopRequireDefault(_Container);
17
18 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
19
20 /**\r
21  * Parses a media feature expression, e.g. `max-width: 10px`, `(color)`\r
22  *\r
23  * @param {string} string - the source expression string, can be inside parens\r
24  * @param {Number} index - the index of `string` in the overall input\r
25  *\r
26  * @return {Array} an array of Nodes, the first element being a media feature,\r
27  *    the secont - its value (may be missing)\r
28  */
29
30 function parseMediaFeature(string) {
31   var index = arguments.length <= 1 || arguments[1] === undefined ? 0 : arguments[1];
32
33   var modesEntered = [{
34     mode: 'normal',
35     character: null
36   }];
37   var result = [];
38   var lastModeIndex = 0;
39   var mediaFeature = '';
40   var colon = null;
41   var mediaFeatureValue = null;
42   var indexLocal = index;
43
44   var stringNormalized = string;
45   // Strip trailing parens (if any), and correct the starting index
46   if (string[0] === '(' && string[string.length - 1] === ')') {
47     stringNormalized = string.substring(1, string.length - 1);
48     indexLocal++;
49   }
50
51   for (var i = 0; i < stringNormalized.length; i++) {
52     var character = stringNormalized[i];
53
54     // If entering/exiting a string
55     if (character === '\'' || character === '"') {
56       if (modesEntered[lastModeIndex].isCalculationEnabled === true) {
57         modesEntered.push({
58           mode: 'string',
59           isCalculationEnabled: false,
60           character: character
61         });
62         lastModeIndex++;
63       } else if (modesEntered[lastModeIndex].mode === 'string' && modesEntered[lastModeIndex].character === character && stringNormalized[i - 1] !== '\\') {
64         modesEntered.pop();
65         lastModeIndex--;
66       }
67     }
68
69     // If entering/exiting interpolation
70     if (character === '{') {
71       modesEntered.push({
72         mode: 'interpolation',
73         isCalculationEnabled: true
74       });
75       lastModeIndex++;
76     } else if (character === '}') {
77       modesEntered.pop();
78       lastModeIndex--;
79     }
80
81     // If a : is met outside of a string, function call or interpolation, than
82     // this : separates a media feature and a value
83     if (modesEntered[lastModeIndex].mode === 'normal' && character === ':') {
84       var mediaFeatureValueStr = stringNormalized.substring(i + 1);
85       mediaFeatureValue = {
86         type: 'value',
87         before: /^(\s*)/.exec(mediaFeatureValueStr)[1],
88         after: /(\s*)$/.exec(mediaFeatureValueStr)[1],
89         value: mediaFeatureValueStr.trim()
90       };
91       // +1 for the colon
92       mediaFeatureValue.sourceIndex = mediaFeatureValue.before.length + i + 1 + indexLocal;
93       colon = {
94         type: 'colon',
95         sourceIndex: i + indexLocal,
96         after: mediaFeatureValue.before,
97         value: ':' };
98       break;
99     }
100
101     mediaFeature += character;
102   }
103
104   // Forming a media feature node
105   mediaFeature = {
106     type: 'media-feature',
107     before: /^(\s*)/.exec(mediaFeature)[1],
108     after: /(\s*)$/.exec(mediaFeature)[1],
109     value: mediaFeature.trim()
110   };
111   mediaFeature.sourceIndex = mediaFeature.before.length + indexLocal;
112   result.push(mediaFeature);
113
114   if (colon !== null) {
115     colon.before = mediaFeature.after;
116     result.push(colon);
117   }
118
119   if (mediaFeatureValue !== null) {
120     result.push(mediaFeatureValue);
121   }
122
123   return result;
124 }
125
126 /**\r
127  * Parses a media query, e.g. `screen and (color)`, `only tv`\r
128  *\r
129  * @param {string} string - the source media query string\r
130  * @param {Number} index - the index of `string` in the overall input\r
131  *\r
132  * @return {Array} an array of Nodes and Containers\r
133  */
134
135 function parseMediaQuery(string) {
136   var index = arguments.length <= 1 || arguments[1] === undefined ? 0 : arguments[1];
137
138   var result = [];
139
140   // How many timies the parser entered parens/curly braces
141   var localLevel = 0;
142   // Has any keyword, media type, media feature expression or interpolation
143   // ('element' hereafter) started
144   var insideSomeValue = false;
145   var node = void 0;
146
147   function resetNode() {
148     return {
149       before: '',
150       after: '',
151       value: ''
152     };
153   }
154
155   node = resetNode();
156
157   for (var i = 0; i < string.length; i++) {
158     var character = string[i];
159     // If not yet entered any element
160     if (!insideSomeValue) {
161       if (character.search(/\s/) !== -1) {
162         // A whitespace
163         // Don't form 'after' yet; will do it later
164         node.before += character;
165       } else {
166         // Not a whitespace - entering an element
167         // Expression start
168         if (character === '(') {
169           node.type = 'media-feature-expression';
170           localLevel++;
171         }
172         node.value = character;
173         node.sourceIndex = index + i;
174         insideSomeValue = true;
175       }
176     } else {
177       // Already in the middle of some alement
178       node.value += character;
179
180       // Here parens just increase localLevel and don't trigger a start of
181       // a media feature expression (since they can't be nested)
182       // Interpolation start
183       if (character === '{' || character === '(') {
184         localLevel++;
185       }
186       // Interpolation/function call/media feature expression end
187       if (character === ')' || character === '}') {
188         localLevel--;
189       }
190     }
191
192     // If exited all parens/curlies and the next symbol
193     if (insideSomeValue && localLevel === 0 && (character === ')' || i === string.length - 1 || string[i + 1].search(/\s/) !== -1)) {
194       if (['not', 'only', 'and'].indexOf(node.value) !== -1) {
195         node.type = 'keyword';
196       }
197       // if it's an expression, parse its contents
198       if (node.type === 'media-feature-expression') {
199         node.nodes = parseMediaFeature(node.value, node.sourceIndex);
200       }
201       result.push(Array.isArray(node.nodes) ? new _Container2.default(node) : new _Node2.default(node));
202       node = resetNode();
203       insideSomeValue = false;
204     }
205   }
206
207   // Now process the result array - to specify undefined types of the nodes
208   // and specify the `after` prop
209   for (var _i = 0; _i < result.length; _i++) {
210     node = result[_i];
211     if (_i > 0) {
212       result[_i - 1].after = node.before;
213     }
214
215     // Node types. Might not be set because contains interpolation/function
216     // calls or fully consists of them
217     if (node.type === undefined) {
218       if (_i > 0) {
219         // only `and` can follow an expression
220         if (result[_i - 1].type === 'media-feature-expression') {
221           node.type = 'keyword';
222           continue;
223         }
224         // Anything after 'only|not' is a media type
225         if (result[_i - 1].value === 'not' || result[_i - 1].value === 'only') {
226           node.type = 'media-type';
227           continue;
228         }
229         // Anything after 'and' is an expression
230         if (result[_i - 1].value === 'and') {
231           node.type = 'media-feature-expression';
232           continue;
233         }
234
235         if (result[_i - 1].type === 'media-type') {
236           // if it is the last element - it might be an expression
237           // or 'and' depending on what is after it
238           if (!result[_i + 1]) {
239             node.type = 'media-feature-expression';
240           } else {
241             node.type = result[_i + 1].type === 'media-feature-expression' ? 'keyword' : 'media-feature-expression';
242           }
243         }
244       }
245
246       if (_i === 0) {
247         // `screen`, `fn( ... )`, `#{ ... }`. Not an expression, since then
248         // its type would have been set by now
249         if (!result[_i + 1]) {
250           node.type = 'media-type';
251           continue;
252         }
253
254         // `screen and` or `#{...} (max-width: 10px)`
255         if (result[_i + 1] && (result[_i + 1].type === 'media-feature-expression' || result[_i + 1].type === 'keyword')) {
256           node.type = 'media-type';
257           continue;
258         }
259         if (result[_i + 2]) {
260           // `screen and (color) ...`
261           if (result[_i + 2].type === 'media-feature-expression') {
262             node.type = 'media-type';
263             result[_i + 1].type = 'keyword';
264             continue;
265           }
266           // `only screen and ...`
267           if (result[_i + 2].type === 'keyword') {
268             node.type = 'keyword';
269             result[_i + 1].type = 'media-type';
270             continue;
271           }
272         }
273         if (result[_i + 3]) {
274           // `screen and (color) ...`
275           if (result[_i + 3].type === 'media-feature-expression') {
276             node.type = 'keyword';
277             result[_i + 1].type = 'media-type';
278             result[_i + 2].type = 'keyword';
279             continue;
280           }
281         }
282       }
283     }
284   }
285   return result;
286 }
287
288 /**\r
289  * Parses a media query list. Takes a possible `url()` at the start into\r
290  * account, and divides the list into media queries that are parsed separately\r
291  *\r
292  * @param {string} string - the source media query list string\r
293  *\r
294  * @return {Array} an array of Nodes/Containers\r
295  */
296
297 function parseMediaList(string) {
298   var result = [];
299   var interimIndex = 0;
300   var levelLocal = 0;
301
302   // Check for a `url(...)` part (if it is contents of an @import rule)
303   var doesHaveUrl = /^(\s*)url\s*\(/.exec(string);
304   if (doesHaveUrl !== null) {
305     var i = doesHaveUrl[0].length;
306     var parenthesesLv = 1;
307     while (parenthesesLv > 0) {
308       var character = string[i];
309       if (character === '(') {
310         parenthesesLv++;
311       }
312       if (character === ')') {
313         parenthesesLv--;
314       }
315       i++;
316     }
317     result.unshift(new _Node2.default({
318       type: 'url',
319       value: string.substring(0, i).trim(),
320       sourceIndex: doesHaveUrl[1].length,
321       before: doesHaveUrl[1],
322       after: /^(\s*)/.exec(string.substring(i))[1]
323     }));
324     interimIndex = i;
325   }
326
327   // Start processing the media query list
328   for (var _i2 = interimIndex; _i2 < string.length; _i2++) {
329     var _character = string[_i2];
330
331     // Dividing the media query list into comma-separated media queries
332     // Only count commas that are outside of any parens
333     // (i.e., not part of function call params list, etc.)
334     if (_character === '(') {
335       levelLocal++;
336     }
337     if (_character === ')') {
338       levelLocal--;
339     }
340     if (levelLocal === 0 && _character === ',') {
341       var _mediaQueryString = string.substring(interimIndex, _i2);
342       var _spaceBefore = /^(\s*)/.exec(_mediaQueryString)[1];
343       result.push(new _Container2.default({
344         type: 'media-query',
345         value: _mediaQueryString.trim(),
346         sourceIndex: interimIndex + _spaceBefore.length,
347         nodes: parseMediaQuery(_mediaQueryString, interimIndex),
348         before: _spaceBefore,
349         after: /(\s*)$/.exec(_mediaQueryString)[1]
350       }));
351       interimIndex = _i2 + 1;
352     }
353   }
354
355   var mediaQueryString = string.substring(interimIndex);
356   var spaceBefore = /^(\s*)/.exec(mediaQueryString)[1];
357   result.push(new _Container2.default({
358     type: 'media-query',
359     value: mediaQueryString.trim(),
360     sourceIndex: interimIndex + spaceBefore.length,
361     nodes: parseMediaQuery(mediaQueryString, interimIndex),
362     before: spaceBefore,
363     after: /(\s*)$/.exec(mediaQueryString)[1]
364   }));
365
366   return result;
367 }