Find me on GitHub
sourcify.js
Sourcify is a code generator that cleans up and applies a consistent formatting style to JavaScript source code. In addition to pretty-printing, Sourcify can be used as the code generator component of a compiler/transpiler (though source map support is still under development). You can pass Sourcify any ES5 ESTree-compliant syntax tree, such as a tree created by Esprima, Acorn, or Espree. You can also pass Sourcify a string, in which case it will parse the string with Esprima and pass that tree to its code generation process. Sourcify takes 38 JSCS-inspired options to give you precise control over semicolons, spacing, linebreaks, indentation, and more. Try out the demos. Experiment with the checkboxes below to sample Sourcify's formatting flexibility. Edit the code snippet to see Sourcify transform it live. It is easier to compare changes if you expand your browser window so the code sits side-by-side.
Sourcify output
Sourcify's main strength is its readable source code. This makes it easy to customize and extend. Compare the following two functions, one from Escodegen, currently the most popular JavaScript code generator, and one from Sourcify. These functions do the same thing. They generate update expressions such as i++. But the Sourcify logic is transparent. You just go through, step-by-step, checking conditions and writing to a string. It is so clear and uncluttered it hardly even looks like JavaScript! It is true that Sourcify's syntactic sugar comes at a slight performance cost. If speed is all you're after, I have also developed a performant version of Sourcify that is 2.5x the speed of Escodegen, as measured using Benchmark in a V8 environment. And even the source of this performant version is fairly easy to understand, customize, and extend.
Sourcify
Escodegen
Sourcify's API consists of just one function.
sourcify(input[, options])
The input parameter can be either an object (the syntax tree to be turned into a string) or a string. If input is a string, Esprima will be used to parse it, and the resulting syntax tree will be passed to the code generation process. The return value will be the generated string.
The options parameter is an object that can contain any of the following properties:
semicolons : boolean default value  true
If this is true, then all statements will end with a semicolon. If this is false, then no statement will end with a semicolon. If this is false, then in order to avoid unintended behavior, defensive semicolons will be inserted at the beginning of expression statements.
preserveComments : boolean default value  true
If this is true, then the original comments will be preserved and included in the generated string. If this is true and you are passing sourcify a syntax tree, make sure the nodes of the syntax tree contain Esprima-style comment data. Currently, this option only works with comments that start in between statements. Any comment that occurs in the middle of a statement will not be preserved. Full comment support is under development.
preserveLinebreaksBetweenStatements : boolean default value  true
If this is true, linebreaks between statements will be preserved as they are in the original. If this is true and you are passing sourcify a syntax tree, make sure the nodes of the syntax tree contain location data. Comments in between statements will "sink down" to rest on top of the bottom statement.
initialIndent : boolean | number | string default value  false
If this is false, then there will be no initial indent. If this is true, the initial indent will be one space. If this is a number, then that many spaces will be used. If this is a string, then that string will be used.
indentIncrement : number | string default value  2
If this is a number, then that many spaces will be used as the indent increment. If this is a string, then that string will be used as the indent increment.
multilineArr : boolean default value  false
If this is true, then array literals will appear on multiple lines, with each element beginning on its own line.
multilineObj : boolean default value  true
If this is true, then object literals will appear on multiple lines, with each key-value pair beginning on its own line.
multilineVar : boolean default value  false
If this is true, then a variable declaration that declares multiple variables will have each variable on its own line.
commaFirstArr : boolean default value  false
If this is true, then array literals will be formatted according to comma-first style.
commaFirstObj : boolean default value  false
If this is true, then object literals will be formatted according to comma-first style.
commaFirstVar : boolean default value  false
If this is true, then variable declarations involving multiple variables will be formatted according to comma-first style.
spaceAfterArrComma : boolean | number | string default value  true
If this is true, then there will be one space after the comma that separates elements in an array literal. If this is false, then there will be no space. If this is a number, then that many spaces will be used. If this is a string, then that string will be used.
spaceAfterBinOp : boolean | number | string default value  true
If this is true, then there will be one space after a binary operator and before the right operand. If this is false, then there will be no space. If this is a number, then that many spaces will be used. If this is a string, then that string will be used.
spaceAfterKeyword : boolean | number | string default value  true
If this is true, then there will be one space after any of the following keywords: catch, do, else, finally, for, if, switch, try, while, and with. If this is false, then there will be no space. If this is a number, then that many spaces will be used. If this is a string, then that string will be used.
spaceAfterObjComma : boolean | number | string default value  true
If this is true, then there will be one space after the comma the occurs after a key-value pair in an object literal. If this is false, then there will be no space. If this is a number, then that many spaces will be used. If this is a string, then that string will be used.
spaceAfterObjKey : boolean | number | string default value  false
If this is true, then there will be one space after the key and before the semicolon in an object literal. If this is false, then there will be no space. If this is a number, then that many spaces will be used. If this is a string, then that string will be used.
spaceAfterPrefixUnOp : boolean | number | string default value  false
If this is true, then there will be one space after a prefix unary operator and before the operand. If this is false, then there will be no space. If this is a number, then that many spaces will be used. If this is a string, then that string will be used.
spaceAfterVarComma : boolean | number | string default value  true
If this is true, then there will be one space after the comma separates variable declarations. If this is false, then there will be no space. If this is a number, then that many spaces will be used. If this is a string, then that string will be used.
spaceBeforeBinOp : boolean | number | string default value  true
If this is true, then there will be one space before the binary operator and after the left operand. If this is false, then there will be no space. If this is a number, then that many spaces will be used. If this is a string, then that string will be used.
spaceBeforeBlock : boolean | number | string default value  true
If this is true, then there will be one space before the block in control flow and looping constructs. If this is false, then there will be no space. If this is a number, then that many spaces will be used. If this is a string, then that string will be used.
spaceBeforeFuncBlock : boolean | number | string default value  false
If this is true, then there will be one space before the block in functions. If this is false, then there will be no space. If this is a number, then that many spaces will be used. If this is a string, then that string will be used.
spaceBeforeFuncParams : boolean | number | string default value  false
If this is true, then there will be one space before the ( that contains the list of function parameters. If this is false, then there will be no space. If this is a number, then that many spaces will be used. If this is a string, then that string will be used.
spaceBeforeKeyword : boolean | number | string default value  true
If this is true, then there will be one space before any of the following keywords: catch, do, else, finally, for, if, switch, try, while, and with. If this is false, then there will be no space. If this is a number, then that many spaces will be used. If this is a string, then that string will be used.
spaceBeforeObjValue : boolean | number | string default value  true
If this is true, then a single space will be inserted after the : and before the property value in an object literal. If this is a number, then that many spaces will be inserted after the : and before the property value in an object literal. If this is a string, then that string will be inserted after the : and before the property value in an object literal.
spaceBeforePostfixUnOp : boolean | number | string default value  false
If this is true, then there will be a space between the operand and post-fix unary operators. If this is a number, then there will be that many spaces between the operand and post-fix unary operators. If this is a string, then that string will be inserted between the operand and post-fix unary operators.
spaceBetweenCallArgs : boolean | number | string default value  true
If this is true, then, in call expressions, there will be a space after the comma that separates arguments. If this is a number, then there will be that many spaces after the comma that separates arguments. If this is a string, then that string will be inserted after the comma that separates arguments.
spaceBetweenFuncParams : boolean | number | string default value  true
If this is true, then, in function declarations and expressions, there will be a space after the comma that separates parameters. If this is a number, then there will be that many spaces after the comma that separates parameters. If this is a string, then that string will be inserted after the comma that separates parameters.
spaceInCallExpr : boolean | number | string default value  false
If this is true, then, in call expressions, there will be a space after the callee and before the opening paren. If this is a number, then there will be that many spaces after the callee and before the opening paren. If this is a string, then that string will be inserted after the callee and before the opening paren.
spaceInConditionalExpr : boolean | number | string default value  true
If this is true, then, in conditional expressions, there will be a space before and after both the ? and the :. If this is a number, then there will be that many spaces before and after both the ? and the :. If this is a string, then that string will be used.
spaceInForStatement : boolean | number | string default value  true
If this is true, then, in traditional for loops, there will be a space after the two required semicolons. If this is a number, then there will be that many spaces after the required semicolons. If this is a string, then that string will be inserted after the required semicolons.
spaceInGenerator : boolean | number | string default value  false
If this is true, then, in generator functions, there will be a space before and after the *. If this is a number, then that many spaces will appear before and after the *. If this is a string, then that string will be inserted both before and after the *.
spaceInsideArrBrackets : boolean | number | string default value  false
If this is true, then, in array literals, there will be a space after the opening square bracket and before the closing square bracket. If this is a number, then that many spaces after the opening square bracket and that many spaces before the closing square bracket. If this is a string, then that string will be inserted after the opening square bracket and that string will be inserted before the closing square bracket.
spaceInsideObjBrackets : boolean | number | string default value  false
If this is true, then, in object literals, there will be a space after the opening curly brace and before the closing curly brace. If this is a number, then that many spaces after the opening curly brace and that many spaces before the closing curly brace. If this is a string, then that string will be inserted after the opening curly brace and that string will be inserted before the closing curly brace.
spaceInsideParensForCallArgs : boolean | number | string default value  false
If this is true, then, in call expressions, there will be a space between each paren and the list of arguments. If this is a number, then that many spaces between each paren and the list of arguments. If this is a string, then that string will be inserted between each paren and the list of arguments
spaceInsideParensForFuncParams : boolean | number | string default value  false
If this is true, then, in function declarations and expressions, there will be a space between each paren and the list of parameters. If this is a number, then that many spaces between each paren and the list of parameters. If this is a string, then that string will be inserted between each paren and the list of parameters.
spaceInsideParensForParenExpr : boolean | number | string default value  false
If this is true, then an expression wrapped in parens will contain a space between each paren and the expression. If this is a number, then that many spaces will be inserted between each paren and the expression. If this is a string, then that string will be inserted between each paren and the expression.
trailingCommaArr : boolean default value  false
If this is true, array literals will contain a trailing comma (i.e., a comma after the last element).
trailingCommaObj : boolean default value  false
If this is true, then object literals will contain a trailing comma (i.e., comma after the last key-value pair).
Install Sourcify with npm or yarn:
npm install sourcify
You can also just download sourcify.js and include it in your html. Just make sure to include Esprima before Sourcify. If you prefer performance over an easy-to-read source code, use sourcify-perf.js instead. Both of these versions rely solely on ES5 features and will work in all modern browsers.
Download sourcify.js
Download sourcify-perf.js

Check out the source on Github.