3 var rocambole = require('rocambole');
4 var indent = require('rocambole-indent');
5 var debug = require('debug')('esformatter:indent');
6 var hooks = require('./hooks');
13 // this hash table is used to map special node types (used only for
14 // indentation) into the real hooks
16 'VariableDeclaration': 'MultipleVariableDeclaration'
23 exports.setOptions = setOptions;
24 function setOptions(opts){
26 indent.setOptions(opts);
30 // transform AST in place
31 exports.transform = transform;
32 function transform(ast) {
33 rocambole.walk(ast, transformNode);
35 if (_opts.AlignComments) {
36 indent.alignComments(ast);
42 function transformNode(node) {
43 var indentLevel = getIndentLevel(node);
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)
53 debug('[transformNode]: hook returned no edges');
61 '[transformNode] type: %s, edges: "%s", "%s"',
63 edges && edges.startToken && edges.startToken.value,
64 edges && edges.endToken && edges.endToken.value
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) {
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
76 indentEdge(edge, indentLevel);
79 indentEdge(edges, indentLevel);
85 function indentEdge(edge, level) {
86 indent.inBetween(edge.startToken, edge.endToken, edge.level || level);
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);