42cdee73ebcd4f554a5dcb70798c2604adc275d9
[platform/framework/web/crosswalk-tizen.git] /
1 "use strict";
2
3 var rocambole = require('rocambole');
4 var indent = require('rocambole-indent');
5 var debug = require('debug')('esformatter:indent');
6 var hooks = require('./hooks');
7
8 // ---
9
10
11 var _opts;
12
13 // this hash table is used to map special node types (used only for
14 // indentation) into the real hooks
15 var _specialTypes = {
16   'VariableDeclaration': 'MultipleVariableDeclaration'
17 };
18
19
20 // ---
21
22
23 exports.setOptions = setOptions;
24 function setOptions(opts){
25   _opts = opts;
26   indent.setOptions(opts);
27 }
28
29
30 // transform AST in place
31 exports.transform = transform;
32 function transform(ast) {
33   rocambole.walk(ast, transformNode);
34   indent.sanitize(ast);
35   if (_opts.AlignComments) {
36     indent.alignComments(ast);
37   }
38   return ast;
39 }
40
41
42 function transformNode(node) {
43   var indentLevel = getIndentLevel(node);
44   if (indentLevel) {
45     var type = node.type;
46     var edges;
47
48     if (type in hooks && hooks[type].getIndentEdges) {
49       edges = hooks[type].getIndentEdges(node, _opts);
50       // for some nodes we might decide that they should not be indented
51       // (complex rules based on context)
52       if (!edges) {
53         debug('[transformNode]: hook returned no edges');
54         return;
55       }
56     } else {
57       edges = node;
58     }
59
60     debug(
61       '[transformNode] type: %s, edges: "%s", "%s"',
62       node.type,
63       edges && edges.startToken && edges.startToken.value,
64       edges && edges.endToken && edges.endToken.value
65     );
66
67     // some complex nodes like IfStatement contains multiple sub-parts that
68     // should be indented, so we allow an Array of edges as well
69     if (Array.isArray(edges)) {
70       edges.forEach(function(edge) {
71         if (!edge) {
72           // to simplify the logic we allow empty/falsy values on the edges
73           // array, that way we can use same logic for single/multiple edges
74           return;
75         }
76         indentEdge(edge, indentLevel);
77       });
78     } else {
79       indentEdge(edges, indentLevel);
80     }
81   }
82 }
83
84
85 function indentEdge(edge, level) {
86   indent.inBetween(edge.startToken, edge.endToken, edge.level || level);
87 }
88
89
90 function getIndentLevel(node) {
91   var value = _opts[node.type];
92   debug('[getIndentLevel] type: %s, value: %s', node.type, value);
93   if (node.type in _specialTypes) {
94     value = value || _opts[_specialTypes[node.type]];
95     debug('[specialNodeType] indent: %s', value);
96   }
97   return value;
98 }
99