UNPKG

coffee-fmt

Version:

a `gofmt` inspired Coffeescript formatter/beautifier.

240 lines (226 loc) 8.01 kB
/* * Just nobody look. * At this, what a disaster! * I blame Coffeescript. */ var COMMENT, HERECOMMENT, IDENTIFIER, INDENT, Lexer, NUMBER, OUTDENT, PADDED_LR_TYPES, STRING, TERMINATOR, fmt, indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; Lexer = require('./lexer').Lexer; INDENT = "INDENT"; OUTDENT = "OUTDENT"; TERMINATOR = "TERMINATOR"; HERECOMMENT = "HERECOMMENT"; COMMENT = "COMMENT"; IDENTIFIER = "IDENTIFIER"; NUMBER = "NUMBER"; STRING = "STRING"; PADDED_LR_TYPES = ["UNARY", "LOGIC", "SHIFT", "COMPARE", "COMPOUND_ASSIGN", "MATH", "RELATION", "FORIN", "FOROF", "INSTANCEOF", "UNLESS", "IF", "THEN", "ELSE", "OWN", "WHEN", "LEADING_WHEN", "=", "->", "FOR", "BY", "RETURN", "UNDEFINED", "NULL", "THROW", "WHILE", "SWITCH", "+", "CLASS", ":", "-"]; fmt = function(code, options) { var CURR_INDENT, CURR_LINE, INDENT_SIZE, comments, fn, formatted_code, i, k, lexer, ref, tokens; lexer = new Lexer(); tokens = lexer.tokenize(code, { rewrite: false, verbose: options.verbose }); formatted_code = ""; CURR_INDENT = ""; CURR_LINE = 0; INDENT_SIZE = options.tab.length; comments = []; tokens.unshift([ 'PROGRAM', '', { first_line: 0, first_column: 0, last_line: 0, last_column: 0 } ]); fn = function(i) { var fn1, inline, j, l, ref1, ref2, ref3, ref4, tmp, token; token = tokens[i]; CURR_INDENT = token[0] === INDENT ? CURR_INDENT + options.tab : token[0] === OUTDENT ? CURR_INDENT.slice(0, -INDENT_SIZE) : CURR_INDENT; if (token[0] === INDENT || token[0] === OUTDENT) { return; } if (token[0] === HERECOMMENT) { if (tokens[i - 1][1] === "\n" || token[2].first_line !== token[2].last_line) { comments.push({ type: HERECOMMENT, text: token[1].trim(), token: token, index: i }); CURR_LINE = token[2].first_line; return; } else if (formatted_code.length && !(formatted_code.charAt(formatted_code.length - 1).match(/\s/))) { formatted_code += " "; } else { formatted_code = formatted_code.trim(); formatted_code += " "; } formatted_code += "### "; token[1] = token[1].trim() + " ###"; } if (token[0] === COMMENT) { if (true) { if ((token[1].split("#")[0].indexOf("\n") === -1) && formatted_code.length) { inline = token[1].split("\n").shift(); if (formatted_code.length && !(formatted_code.charAt(formatted_code.length - 1).match(/\s/))) { formatted_code += " "; } else { formatted_code = formatted_code.trim(); formatted_code += " "; } formatted_code += inline.trim().replace(/^#(\s)*/, "# "); token[1] = token[1].split("\n").slice(1).join("\n"); } comments.push({ type: COMMENT, text: token[1], token: token, index: i }); CURR_LINE = token[2].first_line; return; } } if (token[2].first_line > CURR_LINE) { formatted_code += "\n" + CURR_INDENT; CURR_LINE = token[2].first_line; } if (token.generated) { return; } if (token[0] === TERMINATOR) { return; } if (token[0] === "PROGRAM") { return; } fn1 = function(j) { var bool, lastLineWasBlank, tmp; if (comments[j].text.length === 0) { return; } if (comments[j].type === COMMENT) { tmp = comments[j].text.split("\n"); if (tmp.length) { if (formatted_code.slice(-2) !== "\n\n") { formatted_code += "\n" + CURR_INDENT; } } bool = false; lastLineWasBlank = false; tmp.forEach(function(line, index) { var isBlankLine, text; text = line.split("#"); text = text[1] || text[0]; bool = bool || text.trim(); if (bool) { isBlankLine = !text.trim(); if (lastLineWasBlank && isBlankLine) { formatted_code = formatted_code.slice(0, formatted_code.lastIndexOf("\n")); formatted_code = formatted_code.slice(0, formatted_code.lastIndexOf("\n") + 1); } if (true) { formatted_code += "# " + text.trim(); formatted_code += "\n" + CURR_INDENT; } else { formatted_code += "\n" + CURR_INDENT; } return lastLineWasBlank = isBlankLine; } }); if (lastLineWasBlank) { formatted_code = formatted_code.slice(0, formatted_code.lastIndexOf("\n")); formatted_code = formatted_code.slice(0, formatted_code.lastIndexOf("\n") + 1); return formatted_code += CURR_INDENT; } } else if (comments[j].type === HERECOMMENT) { if (comments[j].token.first_line === comments[j].token.last_line && comments[j].token.first_line === tokens[comments[j].index - 1].last_line && tokens[comments[j].index - 1][1] !== "\n") { formatted_code = formatted_code.slice(0, formatted_code.lastIndexOf("\n")); } if (formatted_code.length && !(formatted_code.charAt(formatted_code.length - 1).match(/\s/))) { formatted_code += " "; } formatted_code += "###\n" + CURR_INDENT; tmp = comments[j].text.split("\n"); tmp.forEach(function(line) { return formatted_code += CURR_INDENT + line.trim() + "\n" + CURR_INDENT; }); return formatted_code += "###\n" + CURR_INDENT; } }; for (j = l = 0, ref1 = comments.length - 1; l <= ref1; j = l += 1) { fn1(j); } comments = []; tmp = ""; if (ref2 = token[0], indexOf.call(PADDED_LR_TYPES, ref2) >= 0) { if (!formatted_code.charAt(formatted_code.length - 1).match(/\s/)) { tmp += " "; } if (token[1] === "==") { tmp += "is"; } else if (token[1] === "!=") { tmp += "isnt"; } else if (token[1] === "!") { tmp += "not"; } else if (token[1] === "&&") { tmp += "and"; } else if (token[1] === "||") { tmp += "or"; } else if (token[1] === "||=") { tmp += "or="; } else if (token[1] === "&&=") { tmp += "and="; } else { tmp += token[1]; } } else if ((ref3 = token[0]) === "@") { if (!formatted_code.charAt(formatted_code.length - 1).match(/\s/)) { tmp += " "; } tmp += token[1]; } else if (token[0] === ",") { if (tokens[i - 1][0] === "IDENTIFIER" || tokens[i - 1][0] === "NUMBER") { formatted_code = formatted_code.trim(); } tmp += token[1]; } else if (token[0] === "IDENTIFIER") { if (tokens[i - 1][0] === "," || tokens[i - 1][0] === "IDENTIFIER" || formatted_code.charAt(formatted_code.length - 1) === ")") { tmp += " "; } tmp += token[1]; } else if (token[0] === "STRING") { if (tokens[i - 1][0] === "," || tokens[i - 1][0] === "IDENTIFIER") { tmp += " "; } tmp += token[1]; } else if (token[0] === "NUMBER") { if (tokens[i - 1][0] === "," || tokens[i - 1][0] === "IDENTIFIER") { tmp += " "; } tmp += token[1]; } else { tmp = token[1]; } if (ref4 = tokens[i - 1][0], indexOf.call(PADDED_LR_TYPES, ref4) >= 0) { if (!formatted_code.charAt(formatted_code.length - 1).match(/\s/) && !tmp.charAt(0).match(/\s/)) { tmp = " " + tmp; } } if (tokens[i - 1][0] === "," && tmp.charAt(0) !== " ") { tmp = " " + tmp; } return formatted_code += tmp; }; for (i = k = 0, ref = tokens.length - 1; k <= ref; i = k += 1) { fn(i); } if (true && formatted_code.slice(-options.newLine.length) !== options.newLine) { formatted_code += options.newLine; } return formatted_code; }; module.exports.format = fmt;