.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / postcss-sass / index.js
1 var postcss = require('postcss');
2 var gonzales = require('gonzales-pe');
3 var Input = require('postcss/lib/input');
4
5 var DEFAULT_RAWS_ROOT = {
6     before:    ''
7 };
8
9 var DEFAULT_RAWS_RULE = {
10     before:    '',
11     between:   ''
12 };
13
14 var DEFAULT_RAWS_DECL = {
15     before:    '',
16     between:   '',
17     semicolon: false
18 };
19
20 var DEFAULT_COMMENT_DECL = {
21     before:    '',
22     left:      '',
23     right:     ''
24 };
25
26 global.postcssSass = {};
27
28 function process(
29     source,
30     node,
31     parent,
32     input
33 ) {
34     if (node.type === 'stylesheet') {
35         // Create and set parameters for Root node
36         var root = postcss.root();
37         root.source = {
38             start: node.start,
39             end: node.end,
40             input: input
41         };
42         // Raws for root node
43         root.raws = {
44             semicolon: DEFAULT_RAWS_ROOT.semicolon,
45             before: DEFAULT_RAWS_ROOT.before
46         };
47         // Store spaces before root (if exist)
48         global.postcssSass.before = '';
49         for (var i = 0; i < node.content.length; i++) {
50             process(source, node.content[i], root, input);
51         }
52         return root;
53     } else if (node.type === 'ruleset') {
54         // Loop to find the deepest ruleset node
55         var pseudoClassFirst = false;
56         // Define new selector
57         var selector = '';
58         global.postcssSass.multiRuleProp = '';
59         for (var rContent = 0; rContent < node.content.length; rContent++ ) {
60             if (node.content[rContent].type === 'block') {
61                 // Create Rule node
62                 var rule = postcss.rule();
63
64                 // Object to store raws for Rule
65                 var rRaws = {
66                     before: global.postcssSass.before ||
67                         DEFAULT_RAWS_RULE.before,
68                     between: DEFAULT_RAWS_RULE.between
69                 };
70
71                 /* Variable to store spaces and symbols
72                  before declaration property */
73                 global.postcssSass.before = '';
74
75                 global.postcssSass.comment = false;
76
77                 // Look up throw all nodes in current ruleset node
78                 for (
79                     var rCurrentContent = 0;
80                     rCurrentContent < node.content.length;
81                     rCurrentContent++
82                 ) {
83                     if (node.content[rCurrentContent].type === 'block') {
84                         process(
85                             source,
86                             node.content[rCurrentContent],
87                             rule,
88                             input
89                         );
90                     }
91                 }
92
93                 if (rule.nodes.length !== 0) {
94                     // Write selector to Rule, and remove last whitespace
95                     rule.selector = selector;
96                     // Set parameters for Rule node
97                     rule.parent = parent;
98                     rule.source = {
99                         start: node.start,
100                         end: node.end,
101                         input: input
102                     };
103                     rule.raws = rRaws;
104                     parent.nodes.push(rule);
105                 }
106             } else if (node.content[rContent].type === 'selector') {
107                 // Creates selector for rule
108                 for (
109                     var sCurrentContent = 0;
110                     sCurrentContent < node.content[rContent].length;
111                     sCurrentContent++
112                 ) {
113                     if (node.content[rContent]
114                         .content[sCurrentContent].type === 'id') {
115                         selector += '#';
116                     } else if (node.content[rContent]
117                         .content[sCurrentContent].type === 'class') {
118                         selector += '.';
119                     } else if (node.content[rContent]
120                         .content[sCurrentContent].type === 'typeSelector') {
121                         if (node.content[rContent]
122                             .content[sCurrentContent + 1] &&
123                             node.content[rContent]
124                                 .content[sCurrentContent + 1]
125                                 .type === 'pseudoClass' &&
126                             pseudoClassFirst) {
127                             selector += ', ';
128                         } else {
129                             pseudoClassFirst = true;
130                         }
131                     } else if (node.content[rContent]
132                         .content[sCurrentContent].type === 'pseudoClass') {
133                         selector += ':';
134                     }
135                     selector += node.content[rContent]
136                         .content[sCurrentContent].content;
137                 }
138             }
139         }
140     } else if (node.type === 'block') {
141         /* If nested rules exist,
142         wrap current rule in new rule node */
143         if (global.postcssSass.multiRule) {
144             var multiRule = postcss.rule();
145             multiRule.source = {
146                 start: {
147                     line: node.start.line - 1,
148                     column: node.start.column
149                 },
150                 end: node.end,
151                 input: input
152             };
153             multiRule.parent = parent;
154             multiRule.selector = global.postcssSass.multiRuleProp;
155             multiRule.raws = {
156                 before: global.postcssSass.before || DEFAULT_RAWS_RULE.before,
157                 between: DEFAULT_RAWS_RULE.between
158             };
159             parent.push(multiRule);
160             parent = multiRule;
161         }
162
163         global.postcssSass.before = '';
164
165         // Looking for declaration node in block node
166         for (var bContent = 0; bContent < node.content.length; bContent++) {
167             process(
168                 source,
169                 node.content[bContent],
170                 parent,
171                 input
172             );
173         }
174     } else if (node.type === 'declaration') {
175         var isBlockInside = false;
176         // Create Declaration node
177         var decl = postcss.decl();
178         decl.prop = '';
179         // Object to store raws for Declaration
180         var dRaws = {
181             before: global.postcssSass.before || DEFAULT_RAWS_DECL.before,
182             between: DEFAULT_RAWS_DECL.between,
183             semicolon: DEFAULT_RAWS_DECL.semicolon
184         };
185
186         global.postcssSass.property = false;
187         global.postcssSass.betweenBefore = false;
188         global.postcssSass.comment = false;
189         // Looking for property and value node in declaration node
190         for (var dContent = 0; dContent < node.content.length; dContent++) {
191             if (node.content[dContent].type === 'property') {
192                 /* global.property to detect is property is
193                 already defined in current object */
194                 global.postcssSass.property = true;
195                 global.postcssSass.multiRuleProp = node.content[dContent]
196                     .content[0].content;
197                 process(
198                     source,
199                     node.content[dContent],
200                     decl,
201                     input
202                 );
203             } else if (node.content[dContent].type === 'propertyDelimiter') {
204                 if (global.postcssSass.property &&
205                     !global.postcssSass.betweenBefore) {
206                     /* If property is already defined and
207                      there's no ':' before it */
208                     dRaws.between += node.content[dContent].content;
209                     global.postcssSass.multiRuleProp += node.content[dContent]
210                         .content;
211                 } else {
212                     /* If ':' goes before property declaration, like
213                     * :width 100px */
214                     global.postcssSass.betweenBefore = true;
215                     dRaws.before += node.content[dContent].content;
216                     global.postcssSass.multiRuleProp += node.content[dContent]
217                         .content;
218                 }
219             } else if (node.content[dContent].type === 'space') {
220                 dRaws.between += node.content[dContent].content;
221             } else if (node.content[dContent].type === 'value') {
222                 // Look up for a value for current property
223                 if (node.content[dContent].content[0].type === 'block') {
224                     isBlockInside = true;
225                     // If nested rules exist
226                     if (typeof node.content[dContent]
227                         .content[0].content === 'object') {
228                         global.postcssSass.multiRule = true;
229                     }
230                     process(
231                         source,
232                         node.content[dContent].content[0],
233                         parent,
234                         input
235                     );
236                 } else if (node.content[dContent]
237                     .content[0].type === 'variable') {
238                     decl.value = '$';
239                     process(
240                         source,
241                         node.content[dContent],
242                         decl,
243                         input
244                     );
245                 } else if (node.content[dContent].content[0].type === 'color') {
246                     decl.value = '#';
247                     process(
248                         source,
249                         node.content[dContent],
250                         decl,
251                         input
252                     );
253                 } else if (node.content[dContent]
254                     .content[0].type === 'number') {
255                     if (node.content[dContent].content.length > 1) {
256                         decl.value = '';
257                         for (
258                             var dCurrentContent = 0;
259                             dCurrentContent < node.content[dContent]
260                                 .content.length;
261                             dCurrentContent++
262                         ) {
263                             decl.value += node.content[dContent]
264                                 .content[dCurrentContent];
265                         }
266                     } else {
267                         process(
268                             source,
269                             node.content[dContent],
270                             decl,
271                             input
272                         );
273                     }
274                 } else {
275                     process(
276                         source,
277                         node.content[dContent],
278                         decl,
279                         input
280                     );
281                 }
282             }
283         }
284
285         global.postcssSass.before = '';
286
287         if (!isBlockInside) {
288             // Set parameters for Declaration node
289             decl.source = {
290                 start: node.start,
291                 end: node.end,
292                 input: input
293             };
294             decl.parent = parent;
295             decl.raws = dRaws;
296             parent.nodes.push(decl);
297         }
298     } else if (node.type === 'property') {
299         // Set property for Declaration node
300         if (node.content[0].type === 'variable') {
301             parent.prop += '$';
302         }
303         parent.prop += node.content[0].content;
304     } else if (node.type === 'value') {
305         if (!parent.value) {
306             parent.value = '';
307         }
308         // Set value for Declaration node
309         if (node.content.length > 0) {
310             for (
311                 var vContent = 0;
312                 vContent < node.content.length;
313                 vContent++
314             ) {
315                 if (node.content[vContent].type === 'important') {
316                     parent.important = true;
317                 } else if (node.content[vContent]
318                     .content.constructor === Array ) {
319                     for (
320                         var vContentParts = 0;
321                         vContentParts < node.content[vContent]
322                             .content.length;
323                         vContentParts++
324                     ) {
325                         parent.value += node.content[vContent]
326                             .content[vContentParts];
327                     }
328                 } else {
329                     parent.value += node.content[vContent].content;
330                 }
331             }
332         } else if (node.content[0].content.constructor === Array) {
333             for (
334                 var vContentFirst = 0;
335                 vContentFirst < node.content[0].content.length;
336                 vContentFirst++
337             ) {
338                 parent.value += node.content[0]
339                     .content[vContentFirst].content;
340             }
341         } else {
342             parent.value += node.content[0].content;
343         }
344     } else if (node.type === 'singlelineComment' ||
345         node.type === 'multilineComment') {
346         // Create a new node for comment
347         var comment = postcss.comment();
348         var text = node.content;
349         // Clear comment text from spaces/symbols
350         var textClear = text.trim();
351         comment.text = textClear;
352         // Found spaces/symbols before comment
353         var left = text.search(/\S/);
354         global.postcssSass.comment = true;
355         // Found spaces/symbols after comment
356         var right = text.length - textClear.length - left;
357         // Raws for current comment node
358         comment.raws = {
359             before: global.postcssSass.before || DEFAULT_COMMENT_DECL.before,
360             left: new Array(left + 1).join(' '),
361             right: new Array(right + 1).join(' ')
362         };
363         // Define type of comment
364         if (node.type === 'singlelineComment') {
365             comment.raws.commentType = 'single';
366         } else if (node.type === 'multilineComment') {
367             comment.raws.commentType = 'multi';
368         }
369         parent.nodes.push(comment);
370     } else if (node.type === 'space') {
371         // Spaces before root and rule
372         if (parent.type === 'root') {
373             global.postcssSass.before += node.content;
374         } else if (parent.type === 'rule') {
375             if (global.postcssSass.comment) {
376                 global.postcssSass.before = '\n' + node.content;
377             } else {
378                 if (global.postcssSass.before === '') {
379                     global.postcssSass.before = '\n';
380                 }
381                 global.postcssSass.before += node.content;
382             }
383         }
384     } else if (node.type === 'declarationDelimiter') {
385         global.postcssSass.before += node.content;
386     }
387     return null;
388 }
389
390 module.exports = function sassToPostCssTree(
391     source,
392     opts
393 ) {
394     var data = {
395         node: gonzales.parse(source.toString('utf8'), { syntax: 'sass' }),
396         input: new Input(source, opts),
397         parent: null
398     };
399     return process(
400         source,
401         data.node,
402         data.parent,
403         data.input);
404 };