UNPKG

esformatter

Version:
126 lines (99 loc) 3.56 kB
'use strict'; var _br = require('rocambole-linebreak'); var _options = require('./options'); var _tk = require('rocambole-token'); var _ws = require('rocambole-whitespace'); var addBrAroundNode = require('./lineBreakAroundNode'); var expressionParentheses = require('./hooks/expressionParentheses'); var hooks = require('./hooks'); var indent = require('./indent'); var plugins = require('./plugins'); var rocambole = require('rocambole'); // --- var _shouldRemoveTrailingWs; // --- exports = module.exports = transform; // used to make sure we don't call setOptions twice when executing `transform` // from inside `format` exports.BYPASS_OPTIONS = {}; // --- function transform(ast, opts) { if (opts !== exports.BYPASS_OPTIONS) { _options.set(opts); } // we store this here to avoid calling `_options.get` for each token _shouldRemoveTrailingWs = Boolean(_options.get('whiteSpace.removeTrailing')); plugins.transformBefore(ast); _tk.eachInBetween(ast.startToken, ast.endToken, preprocessToken); rocambole.moonwalk(ast, transformNode); _tk.eachInBetween(ast.startToken, ast.endToken, postprocessToken); _br.limitBeforeEndOfFile(ast); // indent should come after all other transformations since it depends on // line breaks caused by "parent" nodes, otherwise it will cause conflicts. // it should also happen after the postprocessToken since it adds line breaks // before/after comments and that changes the indent logic indent.transform(ast); // plugin transformation comes after the indentation since we assume user // knows what he is doing (will increase flexibility and allow plugin to // override the indentation logic) // we have an alias "transform" to match v0.3 API, but favor `transformAfter` // moving forward. (we might deprecate "transform" in the future) plugins.transform(ast); plugins.transformAfter(ast); return ast; } function transformNode(node) { plugins.nodeBefore(node); addBrAroundNode(node); var hook = hooks[node.type]; if (hook && 'format' in hook) { hook.format(node); } // empty program doesn't have startToken or endToken if (node.startToken) { // automatic white space comes afterwards since line breaks introduced by // the hooks affects it _ws.limitBefore(node.startToken, node.type); _ws.limitAfter(node.endToken, node.type); } // handle parenthesis automatically since it is needed by multiple node types // and it avoids code duplication and reduces complexity of each hook expressionParentheses.addSpaceInside(node); plugins.nodeAfter(node); } function preprocessToken(token) { if (_tk.isComment(token)) { _br.limit(token, token.type); } plugins.tokenBefore(token); } function postprocessToken(token) { if (_tk.isComment(token)) { processComment(token); } else if (_shouldRemoveTrailingWs && _tk.isWs(token)) { removeTrailingWs(token); } plugins.tokenAfter(token); } function processComment(token) { _ws.limitBefore(token, token.type); // only block comment needs space afterwards if (token.type === 'BlockComment') { _ws.limitAfter(token, token.type); return; } // CommentGroup is composed of multiple LineComment var prev = _tk.findPrevNonEmpty(token); var next = _tk.findNextNonEmpty(token); if (!_tk.isComment(prev)) { _br.limitBefore(token, 'CommentGroup'); } if (!_tk.isComment(next)) { _br.limitAfter(token, 'CommentGroup'); } } function removeTrailingWs(token) { if (_tk.isBr(token.next) || !token.next) { _tk.remove(token); } }