├── test ├── compare │ ├── default │ │ ├── empty_file-in.js │ │ ├── empty_file-out.js │ │ ├── inplace-out.js │ │ ├── array_pattern-out.js │ │ ├── inplace-in.js │ │ ├── array_pattern-in.js │ │ ├── throw_statement-in.js │ │ ├── object_pattern-out.js │ │ ├── throw_statement-out.js │ │ ├── jsx-in.js │ │ ├── jsx-out.js │ │ ├── new_expression-in.js │ │ ├── new_expression-out.js │ │ ├── object_pattern-in.js │ │ ├── do_while_statement-in.js │ │ ├── comma_operator-in.js │ │ ├── README.md │ │ ├── comma_operator-out.js │ │ ├── do_while_statement-out.js │ │ ├── member_expression-out.js │ │ ├── member_expression-in.js │ │ ├── iife-in.js │ │ ├── flow-in.js │ │ ├── flow-out.js │ │ ├── iife-out.js │ │ ├── while_statement-out.js │ │ ├── binary_expression-in.js │ │ ├── binary_expression-out.js │ │ ├── logical_expression-in.js │ │ ├── logical_expression-out.js │ │ ├── while_statement-in.js │ │ ├── arrow_function_expression-out.js │ │ ├── for_statement-in.js │ │ ├── unary_expression-in.js │ │ ├── unary_expression-out.js │ │ ├── arrow_function_expression-in.js │ │ ├── for_statement-out.js │ │ ├── for_of_statement-out.js │ │ ├── for_in_statement-out.js │ │ ├── for_of_statement-in.js │ │ ├── for_in_statement-in.js │ │ ├── conditional_expression-in.js │ │ ├── conditional_expression-out.js │ │ ├── array_expression-in.js │ │ ├── array_expression-out.js │ │ ├── class_declaration-in.js │ │ ├── class_declaration-out.js │ │ ├── comments-out.js │ │ ├── switch_statement-out.js │ │ ├── class_expression-in.js │ │ ├── class_expression-out.js │ │ ├── assignment_expression-in.js │ │ ├── module-out.js │ │ ├── assignment_expression-out.js │ │ ├── switch_statement-in.js │ │ ├── comments-in.js │ │ ├── module-in.js │ │ ├── var-out.js │ │ ├── var-in.js │ │ ├── function_expression-out.js │ │ ├── function_expression-in.js │ │ ├── function_declaration-in.js │ │ ├── function_declaration-out.js │ │ ├── try_statement-out.js │ │ ├── try_statement-in.js │ │ ├── call_expression-out.js │ │ ├── call_expression-in.js │ │ └── obj_expression-in.js │ ├── error │ │ ├── invalid-1.js │ │ ├── invalid.json │ │ └── invalid-2.js │ ├── rc │ │ ├── top-in.js │ │ ├── top-out.js │ │ ├── package │ │ │ ├── package-in.js │ │ │ ├── rc │ │ │ │ ├── nested-in.js │ │ │ │ ├── nested-out.js │ │ │ │ └── .esformatter │ │ │ ├── package-out.js │ │ │ ├── nested │ │ │ │ ├── .esformatter │ │ │ │ ├── pkg_nested-in.js │ │ │ │ ├── pkg_nested-out.js │ │ │ │ └── package.json │ │ │ └── package.json │ │ ├── nested │ │ │ ├── .esformatter │ │ │ ├── nested-in.js │ │ │ └── nested-out.js │ │ └── .esformatter │ ├── custom │ │ ├── commented_config-in.js │ │ ├── object_pattern-in.js │ │ ├── basic_function_indent-in.js │ │ ├── array_bug-in.js │ │ ├── array_bug-out.js │ │ ├── basic_function_indent_2-in.js │ │ ├── commented_config-out.js │ │ ├── basic_function_indent-out.js │ │ ├── object_pattern-out.js │ │ ├── basic_function_indent_2-out.js │ │ ├── assignment_expression-out.js │ │ ├── binary_expression-config.json │ │ ├── assignment_expression-in.js │ │ ├── member_expression-in.js │ │ ├── member_expression-out.js │ │ ├── object_expression-2-in.js │ │ ├── binary_expression-in.js │ │ ├── linebreak-before-eof-in.js │ │ ├── linebreak-before-eof-out.js │ │ ├── linebreak-before-eof-2-in.js │ │ ├── top-level-indent-exception-config.json │ │ ├── variable_declaration-in.js │ │ ├── multi-indent-config.json │ │ ├── binary_expression-out.js │ │ ├── linebreak-before-eof-2-out.js │ │ ├── one-line-var-declaration-out.js │ │ ├── one-line-var-declaration-config.json │ │ ├── one-line-var-declaration-in.js │ │ ├── linebreak-before-eof-2-config.json │ │ ├── linebreak-before-eof-config.json │ │ ├── object_expression-config.json │ │ ├── object_expression-2-out.js │ │ ├── function_expression_bug-in.js │ │ ├── function_expression_bug-out.js │ │ ├── class-in.js │ │ ├── variable_declaration-config.json │ │ ├── variable_declaration-out.js │ │ ├── comment_group-config.json │ │ ├── class-out.js │ │ ├── multi-indent-in.js │ │ ├── argumentlist-config.json │ │ ├── array_bug-config.json │ │ ├── module-config.json │ │ ├── negative_indent-config.json │ │ ├── for_statement-config.json │ │ ├── iife-in.js │ │ ├── conditional_expression-out.js │ │ ├── conditional_expression-in.js │ │ ├── align_comments-config.json │ │ ├── iife-out.js │ │ ├── member_expression-config.json │ │ ├── expression_parentheses-config.json │ │ ├── multi-indent-out.js │ │ ├── iife-config.json │ │ ├── negative_indent-in.js │ │ ├── function_expression_bug-config.json │ │ ├── object_expression-3-in.js │ │ ├── argumentlist-out.js │ │ ├── negative_indent-out.js │ │ ├── object_expression-2-config.json │ │ ├── if_statement_spacy-config.json │ │ ├── argumentlist-in.js │ │ ├── README.md │ │ ├── class-config.json │ │ ├── object_expression-3-out.js │ │ ├── for_in_statement-config.json │ │ ├── for_of_statement-config.json │ │ ├── basic_function_indent_2-config.json │ │ ├── object_pattern-config.json │ │ ├── align_comments-in.js │ │ ├── align_comments-out.js │ │ ├── array_expression-in.js │ │ ├── array_expression-out.js │ │ ├── conditional_expression-config.json │ │ ├── array_expression-2-in.js │ │ ├── assignment_expression-config.json │ │ ├── if_statement_spacy-in.js │ │ ├── for_statement-in.js │ │ ├── call_expression-config.json │ │ ├── if_statement_spacy-out.js │ │ ├── call_expression-in.js │ │ ├── call_expression-out.js │ │ ├── for_statement-out.js │ │ ├── commented_config-config.json │ │ ├── object_expression-3-config.json │ │ ├── function-expression-config.json │ │ ├── switch_statement-config.json │ │ ├── for_in_statement-in.js │ │ ├── for_of_statement-in.js │ │ ├── comment_group-in.js │ │ ├── for_in_statement-out.js │ │ ├── for_of_statement-out.js │ │ ├── switch_statement-out.js │ │ ├── comment_group-out.js │ │ ├── array_expression-2-config.json │ │ ├── top-level-indent-exception-out.js │ │ ├── array_expression-config.json │ │ ├── object_expression-in.js │ │ ├── switch_statement-in.js │ │ ├── if_statement-config.json │ │ ├── top-level-indent-exception-in.js │ │ ├── expression_parentheses-in.js │ │ ├── if_statement-in.js │ │ ├── expression_parentheses-out.js │ │ ├── basic_function_indent-config.json │ │ ├── object_expression-out.js │ │ ├── if_statement-out.js │ │ ├── array_expression-2-out.js │ │ ├── try_statement-config.json │ │ ├── module-out.js │ │ ├── module-in.js │ │ ├── try_statement-in.js │ │ └── try_statement-out.js │ ├── .esformatter │ └── jquery │ │ ├── spacing-in.js │ │ └── spacing-out.js ├── bin │ ├── config.json │ └── node_modules │ │ └── esformatter │ │ ├── lib │ │ ├── fake.js │ │ └── cli.js │ │ └── package.json ├── pipe │ ├── bin │ │ ├── esformatter-pipe-test-1 │ │ └── esformatter-pipe-test-2 │ └── package.json ├── plugin │ ├── package.json │ └── index.js ├── transform.spec.js ├── runner.js ├── pipe.spec.js ├── helpers.js └── api.spec.js ├── lib ├── hooks │ ├── ExportSpecifier.js │ ├── ThrowStatement.js │ ├── UpdateExpression.js │ ├── ExportDefaultDeclaration.js │ ├── SequenceExpression.js │ ├── MethodDefinition.js │ ├── ExportAllDeclaration.js │ ├── ArrayPattern.js │ ├── ObjectPattern.js │ ├── ImportDeclaration.js │ ├── ExportNamedDeclaration.js │ ├── BinaryExpression.js │ ├── UnaryExpression.js │ ├── FunctionDeclaration.js │ ├── SwitchStatement.js │ ├── DoWhileStatement.js │ ├── CatchClause.js │ ├── ClassDeclarationAndExpression.js │ ├── LogicalExpression.js │ ├── AssignmentExpression.js │ ├── MemberExpression.js │ ├── ConditionalExpression.js │ ├── SwitchCase.js │ ├── TryStatement.js │ ├── ImportSpecifier.js │ ├── WhileStatement.js │ ├── ForStatement.js │ ├── ArrowFunctionExpression.js │ ├── ForInStatement.js │ ├── ForOfStatement.js │ ├── ReturnStatement.js │ ├── ArrayExpression.js │ ├── Params.js │ ├── FunctionExpression.js │ ├── VariableDeclaration.js │ └── expressionParentheses.js ├── helpers.js ├── limit.js ├── esformatter.js ├── diff.js ├── preset │ └── jquery.json ├── plugins.js └── hooks.js ├── .gitignore ├── .travis.yml ├── doc └── cli.txt ├── .editorconfig ├── LICENSE.md ├── bin └── esformatter └── package.json /test/compare/default/empty_file-in.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/compare/default/empty_file-out.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/compare/error/invalid-1.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | &foo 5 | -------------------------------------------------------------------------------- /test/compare/default/inplace-out.js: -------------------------------------------------------------------------------- 1 | 2 | var a = 40; 3 | 4 | -------------------------------------------------------------------------------- /test/compare/error/invalid.json: -------------------------------------------------------------------------------- 1 | { 2 | lorem: ipsum 3 | } 4 | -------------------------------------------------------------------------------- /test/compare/rc/top-in.js: -------------------------------------------------------------------------------- 1 | function foo(){ 2 | bar(); 3 | } 4 | -------------------------------------------------------------------------------- /test/compare/custom/commented_config-in.js: -------------------------------------------------------------------------------- 1 | if(true){doStuff()} 2 | -------------------------------------------------------------------------------- /test/compare/rc/top-out.js: -------------------------------------------------------------------------------- 1 | function foo(){ 2 | bar(); 3 | } 4 | -------------------------------------------------------------------------------- /test/bin/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "preset": "default", 3 | "root": true 4 | } 5 | -------------------------------------------------------------------------------- /test/compare/custom/object_pattern-in.js: -------------------------------------------------------------------------------- 1 | var {foo,bar,ipsum} = object; 2 | -------------------------------------------------------------------------------- /test/compare/rc/package/package-in.js: -------------------------------------------------------------------------------- 1 | function foo() { 2 | bar(); 3 | } 4 | -------------------------------------------------------------------------------- /test/compare/rc/package/rc/nested-in.js: -------------------------------------------------------------------------------- 1 | function foo() { 2 | bar(); 3 | } 4 | -------------------------------------------------------------------------------- /test/compare/custom/basic_function_indent-in.js: -------------------------------------------------------------------------------- 1 | function foo(x,y){return x+y;} 2 | -------------------------------------------------------------------------------- /test/compare/rc/package/rc/nested-out.js: -------------------------------------------------------------------------------- 1 | function foo() { 2 | bar(); 3 | } 4 | -------------------------------------------------------------------------------- /test/compare/custom/array_bug-in.js: -------------------------------------------------------------------------------- 1 | []; 2 | 3 | this.element; 4 | 5 | parts = []; 6 | -------------------------------------------------------------------------------- /test/compare/custom/array_bug-out.js: -------------------------------------------------------------------------------- 1 | []; 2 | 3 | this.element; 4 | 5 | parts = []; 6 | -------------------------------------------------------------------------------- /test/compare/custom/basic_function_indent_2-in.js: -------------------------------------------------------------------------------- 1 | function foo(x,y){return x+y;} 2 | -------------------------------------------------------------------------------- /test/compare/custom/commented_config-out.js: -------------------------------------------------------------------------------- 1 | if(true) 2 | { 3 | doStuff() 4 | } 5 | -------------------------------------------------------------------------------- /test/compare/rc/package/package-out.js: -------------------------------------------------------------------------------- 1 | function foo() 2 | { 3 | bar(); 4 | } 5 | -------------------------------------------------------------------------------- /test/compare/custom/basic_function_indent-out.js: -------------------------------------------------------------------------------- 1 | function foo ( x,y ){ return x + y; } 2 | -------------------------------------------------------------------------------- /test/compare/rc/nested/.esformatter: -------------------------------------------------------------------------------- 1 | { 2 | "indent": { 3 | "value": "\t" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /lib/hooks/ExportSpecifier.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = require('./ImportSpecifier'); 4 | -------------------------------------------------------------------------------- /test/compare/custom/object_pattern-out.js: -------------------------------------------------------------------------------- 1 | var { 2 | foo , 3 | bar , 4 | ipsum 5 | } = object; 6 | -------------------------------------------------------------------------------- /test/compare/rc/package/nested/.esformatter: -------------------------------------------------------------------------------- 1 | { 2 | "indent": { 3 | "value": "\t" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/compare/custom/basic_function_indent_2-out.js: -------------------------------------------------------------------------------- 1 | function foo(x, y) 2 | { 3 | return x + y; 4 | } 5 | -------------------------------------------------------------------------------- /test/compare/default/array_pattern-out.js: -------------------------------------------------------------------------------- 1 | var [lorem, ipsum] = arr; 2 | 3 | var [x, y, z] = position; 4 | -------------------------------------------------------------------------------- /test/compare/default/inplace-in.js: -------------------------------------------------------------------------------- 1 | var a = 2 | 3 | 40 4 | 5 | ; 6 | 7 | -------------------------------------------------------------------------------- /test/compare/custom/assignment_expression-out.js: -------------------------------------------------------------------------------- 1 | // keep same line 2 | foo=bar; lorem=123 3 | dolor="amet" 4 | 5 | -------------------------------------------------------------------------------- /test/compare/custom/binary_expression-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "indent": { 3 | "BinaryExpression": 1 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/bin/node_modules/esformatter/lib/fake.js: -------------------------------------------------------------------------------- 1 | throw new Error('this is just a fake file and should not be executed'); 2 | -------------------------------------------------------------------------------- /test/compare/custom/assignment_expression-in.js: -------------------------------------------------------------------------------- 1 | // keep same line 2 | foo=bar; lorem =123 3 | dolor = "amet" 4 | 5 | -------------------------------------------------------------------------------- /test/compare/custom/member_expression-in.js: -------------------------------------------------------------------------------- 1 | obj[prop]; 2 | 3 | // also a MemberExpression 4 | proxy.guid = fn.guid; 5 | -------------------------------------------------------------------------------- /test/compare/custom/member_expression-out.js: -------------------------------------------------------------------------------- 1 | obj[ prop ]; 2 | 3 | // also a MemberExpression 4 | proxy.guid = fn.guid; 5 | -------------------------------------------------------------------------------- /test/compare/rc/nested/nested-in.js: -------------------------------------------------------------------------------- 1 | // it should merge the config files if nested 2 | function foo() { 3 | bar(); 4 | } 5 | -------------------------------------------------------------------------------- /test/compare/rc/package/rc/.esformatter: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "indent": { 4 | "value": "\t" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/compare/rc/nested/nested-out.js: -------------------------------------------------------------------------------- 1 | // it should merge the config files if nested 2 | function foo(){ 3 | bar(); 4 | } 5 | -------------------------------------------------------------------------------- /test/compare/custom/object_expression-2-in.js: -------------------------------------------------------------------------------- 1 | var a = { 2 | foo:123, 3 | "bar":"baz" 4 | , 'lorem': new Date() 5 | } 6 | -------------------------------------------------------------------------------- /test/compare/default/array_pattern-in.js: -------------------------------------------------------------------------------- 1 | var [ lorem , ipsum ] = arr; 2 | 3 | var [ 4 | x, 5 | y, 6 | z 7 | ] = position; 8 | -------------------------------------------------------------------------------- /test/compare/custom/binary_expression-in.js: -------------------------------------------------------------------------------- 1 | bar( 2 | 123 / 3 | 456 * 4 | 0.75 ^ 5 | 255 | 6 | 98 << 7 | 1 - 8 | 42 9 | ); 10 | -------------------------------------------------------------------------------- /test/compare/custom/linebreak-before-eof-in.js: -------------------------------------------------------------------------------- 1 | // This file does have a linebreak before eof, but should not after running esformatter 2 | -------------------------------------------------------------------------------- /test/compare/custom/linebreak-before-eof-out.js: -------------------------------------------------------------------------------- 1 | // This file does have a linebreak before eof, but should not after running esformatter -------------------------------------------------------------------------------- /test/compare/rc/package/nested/pkg_nested-in.js: -------------------------------------------------------------------------------- 1 | // it should merge the config files if nested 2 | function foo() { 3 | bar(); 4 | } 5 | -------------------------------------------------------------------------------- /test/compare/rc/package/nested/pkg_nested-out.js: -------------------------------------------------------------------------------- 1 | // it should merge the config files if nested 2 | function foo() 3 | { 4 | bar(); } 5 | -------------------------------------------------------------------------------- /test/compare/custom/linebreak-before-eof-2-in.js: -------------------------------------------------------------------------------- 1 | // This file does have a linebreak before eof, but should not after running esformatter 2 | -------------------------------------------------------------------------------- /test/compare/custom/top-level-indent-exception-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "indent" : { 3 | "TopLevelFunctionBlock" : 0 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/compare/error/invalid-2.js: -------------------------------------------------------------------------------- 1 | 2 | // invalid RegExp 3 | var r = /[\u{61}-b]/ugetqweasdasdlk; 4 | 5 | // some random invalid tokens 6 | $%899 7 | -------------------------------------------------------------------------------- /test/compare/custom/variable_declaration-in.js: -------------------------------------------------------------------------------- 1 | var asd = 'qwerty'; 2 | 3 | var foo = { a: 123, b: 456 }; 4 | 5 | var lorem = 987, 6 | ipsum = 876; 7 | -------------------------------------------------------------------------------- /test/compare/custom/multi-indent-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "indent": { 3 | "FunctionDeclaration": 8, 4 | "MultipleVariableDeclaration": 2 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/compare/custom/binary_expression-out.js: -------------------------------------------------------------------------------- 1 | bar( 2 | 123 / 3 | 456 * 4 | 0.75 ^ 5 | 255 | 6 | 98 << 7 | 1 - 8 | 42 9 | ); 10 | -------------------------------------------------------------------------------- /test/compare/custom/linebreak-before-eof-2-out.js: -------------------------------------------------------------------------------- 1 | // This file does have a linebreak before eof, but should not after running esformatter 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /test/compare/custom/one-line-var-declaration-out.js: -------------------------------------------------------------------------------- 1 | var var1, var2, 2 | var3 = [], 3 | var4 = {}, 4 | var5 = [var1, var2, var3]; 5 | 6 | var x, y, z; 7 | -------------------------------------------------------------------------------- /test/compare/custom/one-line-var-declaration-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lineBreak" : { 3 | "before" : { 4 | "VariableDeclarationWithoutInit" : 0 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/compare/custom/one-line-var-declaration-in.js: -------------------------------------------------------------------------------- 1 | var var1, var2, 2 | var3 = [], 3 | var4 = {}, 4 | var5 = [var1, var2, var3]; 5 | 6 | var x, y, z; 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __* 2 | coverage/ 3 | /node_modules/ 4 | 5 | # the inplace test only removes the generated file if it's executed 6 | test/compare/default/inplace-in.js.copy 7 | -------------------------------------------------------------------------------- /test/compare/custom/linebreak-before-eof-2-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lineBreak" : { 3 | "before" : { 4 | "EndOfFile" : 5 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/compare/custom/linebreak-before-eof-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lineBreak" : { 3 | "before" : { 4 | "EndOfFile" : 0 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/compare/custom/object_expression-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "whiteSpace" : { 3 | "after" : { 4 | "PropertyName" : 1 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/compare/custom/object_expression-2-out.js: -------------------------------------------------------------------------------- 1 | var a = { foo 2 | : 3 | 123 4 | , "bar" 5 | : 6 | "baz" 7 | , 'lorem' 8 | : 9 | new Date() 10 | } 11 | -------------------------------------------------------------------------------- /test/compare/custom/function_expression_bug-in.js: -------------------------------------------------------------------------------- 1 | class Bug { 2 | fix(author) {} 3 | } 4 | 5 | class BugTwo { 6 | fix( author ) {} 7 | } 8 | 9 | var foo = function () {} 10 | -------------------------------------------------------------------------------- /test/compare/custom/function_expression_bug-out.js: -------------------------------------------------------------------------------- 1 | class Bug { 2 | fix(author) {} 3 | } 4 | 5 | class BugTwo { 6 | fix( author ) {} 7 | } 8 | 9 | var foo = function () {} 10 | -------------------------------------------------------------------------------- /test/compare/custom/class-in.js: -------------------------------------------------------------------------------- 1 | // issue #384 2 | class Foo extends React.Component { 3 | classFun (a, b, c) {}} 4 | 5 | const {foo, bar} = baz 6 | 7 | function regularFun(a, b, c){} 8 | 9 | -------------------------------------------------------------------------------- /test/compare/custom/variable_declaration-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "indent": { 3 | "value": " ", 4 | "SingleVariableDeclaration": 1, 5 | "MultipleVariableDeclaration": 0 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/compare/custom/variable_declaration-out.js: -------------------------------------------------------------------------------- 1 | var asd = 'qwerty'; 2 | 3 | var foo = { 4 | a: 123, 5 | b: 456 6 | }; 7 | 8 | var lorem = 987, 9 | ipsum = 876; 10 | -------------------------------------------------------------------------------- /test/compare/.esformatter: -------------------------------------------------------------------------------- 1 | // this config file makes sure we won't load plugins or use user settings while 2 | // formatting the test files through the CLI 3 | { 4 | "root": true, 5 | "plugins": [] 6 | } 7 | -------------------------------------------------------------------------------- /test/compare/custom/comment_group-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lineBreak": { 3 | "before": { 4 | "CommentGroup": 2 5 | }, 6 | "after": { 7 | "CommentGroup": 2 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/compare/rc/package/nested/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "esformatter": { 3 | "lineBreak": { 4 | "before": { 5 | "FunctionDeclarationClosingBrace" : 0 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lib/hooks/ThrowStatement.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _ws = require('rocambole-whitespace'); 4 | 5 | 6 | exports.format = function ThrowStatement(node) { 7 | _ws.limit(node.startToken, 'ThrowKeyword'); 8 | }; 9 | -------------------------------------------------------------------------------- /test/compare/custom/class-out.js: -------------------------------------------------------------------------------- 1 | // issue #384 2 | class Foo extends React.Component { 3 | classFun (a,b,c) {} 4 | } 5 | 6 | const {foo, bar} = baz 7 | 8 | function regularFun(a,b,c) { 9 | } 10 | 11 | -------------------------------------------------------------------------------- /test/compare/rc/.esformatter: -------------------------------------------------------------------------------- 1 | { 2 | "indent": { 3 | "value": " " 4 | }, 5 | "whiteSpace": { 6 | "before": { 7 | "FunctionDeclarationOpeningBrace" : 0 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/compare/custom/multi-indent-in.js: -------------------------------------------------------------------------------- 1 | function foo() { 2 | bar({ 3 | ipsum: 'dolor' 4 | }); 5 | 6 | function amet() { 7 | return 123; 8 | } 9 | } 10 | 11 | var foo = 123, 12 | bar = 'baz'; 13 | -------------------------------------------------------------------------------- /test/pipe/bin/esformatter-pipe-test-1: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var stdin = require('stdin'); 4 | 5 | stdin(function(source) { 6 | process.stdout.write(source + '\n// ---- esformatter-pipe-test-1 ---\n'); 7 | }); 8 | -------------------------------------------------------------------------------- /test/pipe/bin/esformatter-pipe-test-2: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var stdin = require('stdin'); 4 | 5 | stdin(function(source) { 6 | process.stdout.write(source + '\n// ---- esformatter-pipe-test-2 ---\n'); 7 | }); 8 | -------------------------------------------------------------------------------- /test/compare/custom/argumentlist-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "whiteSpace" : { 3 | "before" : { 4 | "ArgumentList" : 1 5 | }, 6 | "after" : { 7 | "ArgumentList" : 1 8 | } 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /test/compare/custom/array_bug-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "whiteSpace" : { 3 | "before" : { 4 | "MemberExpressionClosing" : 1 5 | }, 6 | "after" : { 7 | "MemberExpressionOpening" : 1 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/compare/custom/module-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "whiteSpace": { 3 | "before": { 4 | "ModuleSpecifierClosingBrace": 3 5 | }, 6 | "after": { 7 | "ModuleSpecifierOpeningBrace": 3 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/compare/default/throw_statement-in.js: -------------------------------------------------------------------------------- 1 | function foo(a) {throw new Error('invalid args') 2 | function b() { 3 | throw Error('no new');} 4 | } 5 | 6 | throw "this is an anti-pattern, never throw string, only Error objects"; 7 | 8 | -------------------------------------------------------------------------------- /test/compare/custom/negative_indent-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "indent": { 3 | // yes, you can set negative values. "0" is the real noop. 4 | "ObjectExpression": -1, 5 | "ArrayExpression": -2, 6 | "IfStatement": 0 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/compare/custom/for_statement-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "whiteSpace" : { 3 | "before" : { 4 | "ForStatementExpressionClosing" : 1 5 | }, 6 | "after" : { 7 | "ForStatementExpressionOpening" : 1 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/bin/node_modules/esformatter/lib/cli.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.parse = function() { 4 | return null; 5 | }; 6 | 7 | exports.run = function() { 8 | console.log('fake-esformatter v0.0.0-alpha'); 9 | process.exit(0); 10 | }; 11 | -------------------------------------------------------------------------------- /test/compare/custom/iife-in.js: -------------------------------------------------------------------------------- 1 | // issue #223 2 | (function() { 3 | var x = 1; 4 | foo(bar(), baz()); 5 | }()); 6 | 7 | // issue #250 8 | (function( $ ) { 9 | x; 10 | }( jQuery )); 11 | 12 | ;!function(x){ 13 | console.log(x) 14 | }('bar') 15 | -------------------------------------------------------------------------------- /test/compare/default/object_pattern-out.js: -------------------------------------------------------------------------------- 1 | const {p, a, c, k, e, f} = g; 2 | const {Link} = require('something'); 3 | const {link, button} = require('another'); 4 | 5 | var {foo, bar} = object; 6 | 7 | var {type, parties, sentences, ...props} = this.props; 8 | -------------------------------------------------------------------------------- /test/compare/custom/conditional_expression-out.js: -------------------------------------------------------------------------------- 1 | // test the opposite of default settings 2 | a ?foo():bar(); 3 | 4 | b = (dolor !== amet) ?'ipsum':'dolor'; 5 | 6 | if (true) { 7 | c = !a ?(!foo ?d:function() { 8 | return a; 9 | }):b; 10 | } 11 | -------------------------------------------------------------------------------- /test/compare/default/throw_statement-out.js: -------------------------------------------------------------------------------- 1 | function foo(a) { 2 | throw new Error('invalid args') 3 | function b() { 4 | throw Error('no new'); 5 | } 6 | } 7 | 8 | throw "this is an anti-pattern, never throw string, only Error objects"; 9 | 10 | -------------------------------------------------------------------------------- /test/compare/custom/conditional_expression-in.js: -------------------------------------------------------------------------------- 1 | // test the opposite of default settings 2 | a?foo():bar(); 3 | 4 | b = (dolor!==amet) ? 'ipsum': 'dolor'; 5 | 6 | if(true){ 7 | c = !a ?(!foo?d : function(){ 8 | return a; 9 | }):b; 10 | } 11 | -------------------------------------------------------------------------------- /test/bin/node_modules/esformatter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "esformatter", 4 | "description": "this is a fake version of esformatter just to test if CLI can use local version", 5 | "version": "0.0.0-alpha", 6 | "main": "lib/fake.js" 7 | } 8 | -------------------------------------------------------------------------------- /test/compare/custom/align_comments-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "indent": { 3 | // using the PascalCase format to ensure we support old format 4 | // this will be deprecated during v1.0!!! favor "alignComments" 5 | // instead 6 | "AlignComments": false 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/compare/custom/iife-out.js: -------------------------------------------------------------------------------- 1 | // issue #223 2 | ( function() { 3 | var x = 1; 4 | foo( bar(), baz() ); 5 | }() ); 6 | 7 | // issue #250 8 | ( function( $ ) { 9 | x; 10 | }( jQuery ) ); 11 | 12 | ;!function( x ) { 13 | console.log( x ) 14 | }( 'bar' ) 15 | -------------------------------------------------------------------------------- /test/compare/custom/member_expression-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "whiteSpace" : { 3 | "before" : { 4 | "MemberExpressionClosing" : 1 5 | }, 6 | "after" : { 7 | "MemberExpressionOpening" : 1 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/compare/custom/expression_parentheses-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "whiteSpace" : { 3 | "before" : { 4 | "ExpressionClosingParentheses" : 1 5 | }, 6 | "after" : { 7 | "ExpressionOpeningParentheses" : 1 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/compare/default/jsx-in.js: -------------------------------------------------------------------------------- 1 | var HelloMessage = React.createClass({ 2 | // borrowed from react documentation 3 | render: function() { 4 | // render 5 | return
Hello {this.props.name}
; 6 | } 7 | }); 8 | 9 | React.render(, mountNode); 10 | -------------------------------------------------------------------------------- /test/compare/rc/package/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "esformatter": { 3 | "preset": "default", 4 | "indent": { 5 | "value": " " 6 | }, 7 | "lineBreak": { 8 | "before": { 9 | "FunctionDeclarationOpeningBrace" : 1 10 | } 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/compare/default/jsx-out.js: -------------------------------------------------------------------------------- 1 | var HelloMessage = React.createClass({ 2 | // borrowed from react documentation 3 | render: function() { 4 | // render 5 | return
Hello {this.props.name}
; 6 | } 7 | }); 8 | 9 | React.render(, mountNode); 10 | -------------------------------------------------------------------------------- /lib/hooks/UpdateExpression.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _tk = require('rocambole-token'); 4 | 5 | exports.format = function UpdateExpression(node) { 6 | // XXX: should never have spaces or line breaks before/after "++" and "--"! 7 | _tk.removeEmptyInBetween(node.startToken, node.endToken); 8 | }; 9 | -------------------------------------------------------------------------------- /test/compare/default/new_expression-in.js: -------------------------------------------------------------------------------- 1 | // issue #254 2 | var now = new Date(); 3 | var midnight = new Date( 4 | now.getFullYear(), now.getMonth(), now.getDate() + 1, 5 | 0, 0, 0 6 | ); 7 | 8 | // issue #318 9 | var time = new Date; 10 | 11 | // issue #321 12 | var foo = new 13 | Ctor(); 14 | -------------------------------------------------------------------------------- /test/compare/default/new_expression-out.js: -------------------------------------------------------------------------------- 1 | // issue #254 2 | var now = new Date(); 3 | var midnight = new Date( 4 | now.getFullYear(), now.getMonth(), now.getDate() + 1, 5 | 0, 0, 0 6 | ); 7 | 8 | // issue #318 9 | var time = new Date; 10 | 11 | // issue #321 12 | var foo = new Ctor(); 13 | -------------------------------------------------------------------------------- /test/compare/default/object_pattern-in.js: -------------------------------------------------------------------------------- 1 | const {p, a, c, k, e, f} = g; 2 | const { Link } = require('something'); 3 | const { link, button } = require('another'); 4 | 5 | var { 6 | foo, 7 | bar 8 | } 9 | = object; 10 | 11 | var { type , parties, sentences, ...props } = this.props; 12 | -------------------------------------------------------------------------------- /test/plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "esformatter-test-plugin", 4 | "version": "1.0.0", 5 | "description": "test if esformatter is able to load locally installed plugins from the cli", 6 | "main": "index.js", 7 | "author": "Miller Medeiros", 8 | "license": "ISC" 9 | } 10 | -------------------------------------------------------------------------------- /test/compare/custom/multi-indent-out.js: -------------------------------------------------------------------------------- 1 | function foo() { 2 | bar({ 3 | ipsum: 'dolor' 4 | }); 5 | 6 | function amet() { 7 | return 123; 8 | } 9 | } 10 | 11 | var foo = 123, 12 | bar = 'baz'; 13 | -------------------------------------------------------------------------------- /test/compare/custom/iife-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "whiteSpace": { 3 | "before": { 4 | "ArgumentList": 1, 5 | "IIFEClosingParentheses": 1, 6 | "ParameterList": 1 7 | }, 8 | "after": { 9 | "ArgumentList": 1, 10 | "IIFEOpeningParentheses": 1, 11 | "ParameterList": 1 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/compare/custom/negative_indent-in.js: -------------------------------------------------------------------------------- 1 | function foo() { 2 | function dolor(bar) { 3 | var arr = []; 4 | if (bar) { 5 | arr = [ 6 | 'weird', 7 | 'indent' 8 | ]; 9 | obj = { 10 | 'yes': 'i know it\'s weird', 11 | 'but': 'it tests the rocambole-indent negative rule' 12 | } 13 | } 14 | return arr; 15 | } 16 | return dolor; 17 | } 18 | -------------------------------------------------------------------------------- /test/compare/custom/function_expression_bug-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "indent" : { 3 | "value": " " 4 | }, 5 | 6 | "whiteSpace" : { 7 | "value" : " ", 8 | "before" : { 9 | "ParameterList" : -1 10 | }, 11 | 12 | "after" : { 13 | "FunctionReservedWord": 1, 14 | "ParameterList" : -1 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.12" 4 | script: 5 | - "npm test --coverage" 6 | - "npm run-script lint" 7 | branches: 8 | only: 9 | - master 10 | notifications: 11 | irc: 12 | channels: 13 | - "irc.freenode.org#esformatter" 14 | on_success: change 15 | use_notice: true 16 | skip_join: true 17 | -------------------------------------------------------------------------------- /test/compare/custom/object_expression-3-in.js: -------------------------------------------------------------------------------- 1 | x({ a:1}); 2 | y({ 3 | a: 1 4 | }); 5 | $.each({ div: "#list1", ul: "#navigation", dl: "#accordion-dl" }); 6 | 7 | var x ={ foo:{ bar: true} }; 8 | var y= {a: b, c:d, e:{ f: g } }; 9 | x = { 10 | props: { 11 | // comment 12 | x: 1 13 | } 14 | }; 15 | x = { 16 | b: function b() { 17 | a(); 18 | }, 19 | a: b 20 | }; 21 | -------------------------------------------------------------------------------- /test/compare/custom/argumentlist-out.js: -------------------------------------------------------------------------------- 1 | call(); 2 | call( x ); 3 | call( function() { 4 | something(); 5 | } ); 6 | call( {} ); 7 | call( { 8 | x: 1 9 | } ); 10 | call( x, { 11 | x: 1 12 | } ); 13 | call( x, function() { 14 | x(); 15 | } ); 16 | call( function() { 17 | x(); 18 | }, x ); 19 | call( { 20 | x: 1 21 | }, x ); 22 | call( [] ); 23 | call( [x, y] ); 24 | -------------------------------------------------------------------------------- /test/compare/custom/negative_indent-out.js: -------------------------------------------------------------------------------- 1 | function foo() { 2 | function dolor(bar) { 3 | var arr = []; 4 | if (bar) { 5 | arr = [ 6 | 'weird', 7 | 'indent' 8 | ]; 9 | obj = { 10 | 'yes': 'i know it\'s weird', 11 | 'but': 'it tests the rocambole-indent negative rule' 12 | } 13 | } 14 | return arr; 15 | } 16 | return dolor; 17 | } 18 | -------------------------------------------------------------------------------- /test/compare/custom/object_expression-2-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lineBreak": { 3 | "before": { 4 | "PropertyName": 0, 5 | "PropertyValue": 1 6 | }, 7 | 8 | "after": { 9 | "PropertyName": 1, 10 | "PropertyValue": 1 11 | } 12 | }, 13 | 14 | "whiteSpace": { 15 | "before": { 16 | "PropertyName": 1 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/hooks/ExportDefaultDeclaration.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _br = require('rocambole-linebreak'); 4 | var _tk = require('rocambole-token'); 5 | var _ws = require('rocambole-whitespace'); 6 | 7 | exports.format = function ExportDefaultDeclaration(node) { 8 | var def = _tk.findNext(node.startToken, 'default'); 9 | _br.limit(def, 0); 10 | _ws.limit(def, 1); 11 | }; 12 | -------------------------------------------------------------------------------- /test/compare/default/do_while_statement-in.js: -------------------------------------------------------------------------------- 1 | do{console.log(i++)}while(i<100); do{i--}while(i); 2 | 3 | do n--; while(n&&foo()); 4 | 5 | do n--; while(n&&foo());do++i;while(amet(i)); 6 | 7 | // issue #256 8 | function main() { 9 | do if (true) return 1; while (true); 10 | } 11 | 12 | function main() { 13 | do 14 | if (true) return 1; 15 | while (true); 16 | } 17 | -------------------------------------------------------------------------------- /test/compare/custom/if_statement_spacy-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "whiteSpace" : { 3 | "before" : { 4 | "IfStatementConditionalOpening" : 1, 5 | "IfStatementConditionalClosing" : 1 6 | }, 7 | "after" : { 8 | "IfStatementConditionalOpening" : 1, 9 | "IfStatementConditionalClosing" : 1 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/compare/custom/argumentlist-in.js: -------------------------------------------------------------------------------- 1 | call(); 2 | call( x ); 3 | call( function() { 4 | something(); 5 | } ); 6 | call( {} ); 7 | call( { 8 | x : 1 9 | } ); 10 | call( x, { 11 | x : 1 12 | } ); 13 | call( x, function() { 14 | x(); 15 | } ); 16 | call( function() { 17 | x(); 18 | }, x ); 19 | call( { 20 | x : 1 21 | }, x ); 22 | call( [] ); 23 | call( [x, y] ); 24 | -------------------------------------------------------------------------------- /test/compare/custom/README.md: -------------------------------------------------------------------------------- 1 | # custom settings tests 2 | 3 | These files are used to test custom settings. It should try to test the 4 | *opposite* of the default settings whenever possible. 5 | 6 | `foo_bar-in.js` will be used as input and will be compared with 7 | `foo_bar-out.js`, `foo_bar-config.json` will be passed as the custom settings 8 | on the `esformatter.parse()` call. 9 | 10 | -------------------------------------------------------------------------------- /test/compare/custom/class-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "indent" : { 3 | "value": " " 4 | }, 5 | 6 | "whiteSpace" : { 7 | "value" : " ", 8 | "before" : { 9 | "ParameterList" : -1 10 | }, 11 | 12 | "after" : { 13 | "FunctionReservedWord": 1, 14 | "MethodDefinitionName": 1, 15 | "ParameterComma" : 0, 16 | "ParameterList" : -1 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/compare/custom/object_expression-3-out.js: -------------------------------------------------------------------------------- 1 | x({ a: 1 }); 2 | y({ 3 | a: 1 4 | }); 5 | $.each({ div: "#list1", ul: "#navigation", dl: "#accordion-dl" }); 6 | 7 | var x = { foo: { bar: true } }; 8 | var y = { a: b, c: d, e: { f: g } }; 9 | x = { 10 | props: { 11 | // comment 12 | x: 1 13 | } 14 | }; 15 | x = { 16 | b: function b() { 17 | a(); 18 | }, 19 | a: b 20 | }; 21 | -------------------------------------------------------------------------------- /test/compare/default/comma_operator-in.js: -------------------------------------------------------------------------------- 1 | // SequenceExpression (aka. comma operator) 2 | 3 | a,b 4 | a,b,c 5 | 6 | a=3,foo(), bar() ,"baz",c 7 | 8 | it="is" , ("a"),(trap()) 9 | 10 | // borrowed from signals.min test a bug related to line breaks and indent 11 | if(e!==-1){if(a =this._bindings[e],a.isOnce()!==b)throw Error('foo');}else a=new h(this,a,b,c,d),this._addBinding(a); 12 | 13 | -------------------------------------------------------------------------------- /test/compare/custom/for_in_statement-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lineBreak" : { 3 | "before" : { 4 | "ForInStatementOpeningBrace" : 1 5 | } 6 | }, 7 | "whiteSpace" : { 8 | "before" : { 9 | "ForInStatementExpressionClosing" : 1 10 | }, 11 | "after" : { 12 | "ForInStatementExpressionOpening" : 1 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/compare/custom/for_of_statement-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lineBreak" : { 3 | "before" : { 4 | "ForOfStatementOpeningBrace" : 1 5 | } 6 | }, 7 | "whiteSpace" : { 8 | "before" : { 9 | "ForOfStatementExpressionClosing" : 1 10 | }, 11 | "after" : { 12 | "ForOfStatementExpressionOpening" : 1 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/compare/custom/basic_function_indent_2-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lineBreak" : { 3 | "before" : { 4 | "FunctionDeclarationOpeningBrace" : 1, 5 | "FunctionDeclarationClosingBrace" : 1, 6 | "ReturnStatement" : 1 7 | }, 8 | "after" : { 9 | "FunctionDeclarationOpeningBrace" : 1, 10 | "ReturnStatement" : 1 11 | } 12 | } 13 | } 14 | 15 | -------------------------------------------------------------------------------- /test/compare/custom/object_pattern-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lineBreak": { 3 | "before": { 4 | "ObjectPatternClosingBrace": 1 5 | }, 6 | "after": { 7 | "ObjectPatternOpeningBrace": 1, 8 | "ObjectPatternComma": 1 9 | } 10 | }, 11 | "whiteSpace": { 12 | "before": { 13 | "ObjectPatternComma": 1 14 | }, 15 | "after": { 16 | "ObjectPatternComma": 1 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/compare/default/README.md: -------------------------------------------------------------------------------- 1 | # default settings tests 2 | 3 | These files are used to test the default settings. 4 | 5 | The default settings should be as *conservative* as possible, [Google 6 | JavaScript Style 7 | Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml) 8 | should be used as a reference. 9 | 10 | `foo_bar-in.js` will be used as input and will be compared with `foo_bar-out.js`. 11 | 12 | -------------------------------------------------------------------------------- /test/compare/default/comma_operator-out.js: -------------------------------------------------------------------------------- 1 | // SequenceExpression (aka. comma operator) 2 | 3 | a, b 4 | a, b, c 5 | 6 | a = 3, foo(), bar(), "baz", c 7 | 8 | it = "is", ("a"), (trap()) 9 | 10 | // borrowed from signals.min test a bug related to line breaks and indent 11 | if (e !== -1) { 12 | if (a = this._bindings[e], a.isOnce() !== b) 13 | throw Error('foo'); 14 | } else a = new h(this, a, b, c, d), this._addBinding(a); 15 | 16 | -------------------------------------------------------------------------------- /test/compare/custom/align_comments-in.js: -------------------------------------------------------------------------------- 1 | // comment alignment (#209) 2 | switch (foo) { 3 | case bar: 4 | // lorem 5 | baz(); 6 | // falls through 7 | // yes, this should be aligned too 8 | 9 | // this should be at same indent level as `baz();` 10 | case biz: 11 | what(); 12 | } 13 | 14 | // comment alignment (#270) 15 | try { 16 | bla(); 17 | // comment 18 | // too 19 | } catch (e) { 20 | throw e; 21 | } 22 | -------------------------------------------------------------------------------- /test/compare/custom/align_comments-out.js: -------------------------------------------------------------------------------- 1 | // comment alignment (#209) 2 | switch (foo) { 3 | case bar: 4 | // lorem 5 | baz(); 6 | // falls through 7 | // yes, this should be aligned too 8 | 9 | // this should be at same indent level as `baz();` 10 | case biz: 11 | what(); 12 | } 13 | 14 | // comment alignment (#270) 15 | try { 16 | bla(); 17 | // comment 18 | // too 19 | } catch (e) { 20 | throw e; 21 | } 22 | -------------------------------------------------------------------------------- /test/compare/custom/array_expression-in.js: -------------------------------------------------------------------------------- 1 | [ 2 | 3 | ]; 4 | 5 | [1,2,3]; 6 | 7 | [1,2,[3,4,[5,6,[7,8,9]]]]; 8 | 9 | function fn(){ 10 | return [4,5,[6, 7 , 8 ]]; 11 | } 12 | 13 | // issue #12 14 | var tuples = [ 15 | // comment test 16 | ["resolve", "done", "bla", "resolved"], 17 | ["reject", "fail", "lorem", "rejected"], 18 | [ 19 | ["lorem", "ipsum"] 20 | ], 21 | ["notify", "progress", "ipsum"] 22 | ]; 23 | -------------------------------------------------------------------------------- /test/compare/default/do_while_statement-out.js: -------------------------------------------------------------------------------- 1 | do { 2 | console.log(i++) 3 | } while (i < 100); 4 | do { 5 | i-- 6 | } while (i); 7 | 8 | do n--; while (n && foo()); 9 | 10 | do n--; while (n && foo()); 11 | do ++i; while (amet(i)); 12 | 13 | // issue #256 14 | function main() { 15 | do 16 | if (true) return 1; 17 | while (true); 18 | } 19 | 20 | function main() { 21 | do 22 | if (true) return 1; 23 | while (true); 24 | } 25 | -------------------------------------------------------------------------------- /lib/hooks/SequenceExpression.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _ws = require('rocambole-whitespace'); 4 | 5 | 6 | exports.format = function SequenceExpression(node) { 7 | node.expressions.forEach(function(expr, i) { 8 | if (i) { 9 | var operator = expr.startToken.prev; 10 | while (operator.value !== ',') { 11 | operator = operator.prev; 12 | } 13 | _ws.limit(operator, 'CommaOperator'); 14 | } 15 | }); 16 | }; 17 | -------------------------------------------------------------------------------- /lib/hooks/MethodDefinition.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var ws = require('rocambole-whitespace'); 4 | var br = require('rocambole-linebreak'); 5 | 6 | exports.format = function MethodDefinition(node) { 7 | br.limitAfter(node.startToken, 0); 8 | // limit to one space after get/set/static 9 | if (node.startToken !== node.key) { 10 | ws.limitAfter(node.startToken, 1); 11 | } 12 | ws.limitAfter(node.key.endToken, 'MethodDefinitionName'); 13 | }; 14 | -------------------------------------------------------------------------------- /test/compare/custom/array_expression-out.js: -------------------------------------------------------------------------------- 1 | []; 2 | 3 | [ 1 ,2 ,3 ]; 4 | 5 | [ 1 ,2 ,[ 3 ,4 ,[ 5 ,6 ,[ 7 ,8 ,9 ] ] ] ]; 6 | 7 | function fn() { 8 | return [ 4 ,5 ,[ 6 ,7 ,8 ] ]; 9 | } 10 | 11 | // issue #12 12 | var tuples = [ 13 | // comment test 14 | [ "resolve" ,"done" ,"bla" ,"resolved" ] , 15 | [ "reject" ,"fail" ,"lorem" ,"rejected" ] , 16 | [ 17 | [ "lorem" ,"ipsum" ] 18 | ] , 19 | [ "notify" ,"progress" ,"ipsum" ] 20 | ]; 21 | -------------------------------------------------------------------------------- /test/compare/custom/conditional_expression-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "indent": { 3 | "ConditionalExpression": 0 4 | }, 5 | "whiteSpace" : { 6 | "before" : { 7 | "ConditionalExpressionConsequent" : 0, 8 | "ConditionalExpressionAlternate" : 0 9 | }, 10 | "after" : { 11 | "ConditionalExpressionConsequent" : 0, 12 | "ConditionalExpressionTest" : 1 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/pipe/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "esformatter-pipe-test", 4 | "version": "1.0.0", 5 | "description": "used to test esformatter pipe option", 6 | "author": "Miller Medeiros", 7 | "bin": { 8 | "esformatter-pipe-test-1": "./bin/esformatter-pipe-test-1", 9 | "esformatter-pipe-test-2": "./bin/esformatter-pipe-test-2" 10 | }, 11 | "license": "ISC", 12 | "dependencies": { 13 | "stdin": "0.0.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/compare/default/member_expression-out.js: -------------------------------------------------------------------------------- 1 | obj[prop] = foo.bar; 2 | 3 | BarNamespace['Bar'].Bar["Bar"]('bar').Bar("bar", "bar") 4 | 5 | // should remove these line breaks 6 | foo.bar.ipum(); 7 | 8 | // should NOT remove line breaks in this case 9 | lorem 10 | .ipsum 11 | .dolor(); 12 | 13 | // issue #378 14 | expected[property] = group[property] 15 | expect(foo) 16 | 17 | bar = f[ 18 | 'loremipsumdolorsitamet' + a + '_' + 'somethig_else' 19 | ] 20 | ipsum(bar) 21 | -------------------------------------------------------------------------------- /lib/hooks/ExportAllDeclaration.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _br = require('rocambole-linebreak'); 4 | var _tk = require('rocambole-token'); 5 | var _ws = require('rocambole-whitespace'); 6 | 7 | exports.format = function ExportAllDeclaration(node) { 8 | var star = _tk.findNext(node.startToken, '*'); 9 | _br.limit(star, 0); 10 | _ws.limit(star, 1); 11 | 12 | var fromKeyword = _tk.findNext(node.startToken, 'from'); 13 | _br.limit(fromKeyword, 0); 14 | _ws.limit(fromKeyword, 1); 15 | }; 16 | -------------------------------------------------------------------------------- /test/compare/custom/array_expression-2-in.js: -------------------------------------------------------------------------------- 1 | [ 2 | 3 | ]; 4 | 5 | [1,2,3]; 6 | 7 | [1,2,[3,4,[5,6,[7,8,9]]]]; 8 | 9 | function fn(){ 10 | // IMPORTANT: we can't break lines here because of ASI!!! 11 | return [4,5,[6, 7 , 8 ]]; 12 | } 13 | 14 | // issue #12 15 | var tuples = [ 16 | // comment test 17 | ["resolve", "done", "bla", "resolved"], 18 | ["reject", "fail", "lorem", "rejected"], 19 | [ 20 | ["lorem", "ipsum"] 21 | ], 22 | ["notify", "progress", "ipsum"] 23 | ]; 24 | -------------------------------------------------------------------------------- /test/compare/default/member_expression-in.js: -------------------------------------------------------------------------------- 1 | obj[ prop ] = foo . bar; 2 | 3 | BarNamespace [ 'Bar' ] . Bar [ "Bar" ] ( 'bar' ) . Bar ( "bar", "bar" ) 4 | 5 | // should remove these line breaks 6 | foo. 7 | bar. 8 | ipum(); 9 | 10 | // should NOT remove line breaks in this case 11 | lorem 12 | .ipsum 13 | .dolor(); 14 | 15 | // issue #378 16 | expected[property] = group[property] 17 | expect(foo) 18 | 19 | bar = f[ 20 | 'loremipsumdolorsitamet' + a + '_' + 'somethig_else' 21 | ] 22 | ipsum(bar) 23 | -------------------------------------------------------------------------------- /test/compare/custom/assignment_expression-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lineBreak" : { 3 | "before" : { 4 | "AssignmentExpression" : -1 5 | }, 6 | "after" : { 7 | "AssignmentExpression" : -1 8 | } 9 | }, 10 | "whiteSpace" : { 11 | "before" : { 12 | "AssignmentExpression" : 1, 13 | "AssignmentOperator" : 0 14 | }, 15 | "after" : { 16 | "AssignmentOperator" : 0 17 | } 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /lib/hooks/ArrayPattern.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var limit = require('../limit'); 4 | var tk = require('rocambole-token'); 5 | 6 | exports.format = function ArrayPattern(node) { 7 | limit.around(node.startToken, 'ArrayPatternOpening'); 8 | limit.around(node.endToken, 'ArrayPatternClosing'); 9 | 10 | node.elements.forEach(function(el) { 11 | var comma = tk.findNext(el.endToken, [',', ']']); 12 | if (comma.value === ',') { 13 | limit.around(comma, 'ArrayPatternComma'); 14 | } 15 | }); 16 | }; 17 | -------------------------------------------------------------------------------- /test/compare/custom/if_statement_spacy-in.js: -------------------------------------------------------------------------------- 1 | if(true){doStuff()} 2 | 3 | if( foo ||bar ){ if (bar === 'bar'){ 4 | // nested 5 | log('nested if'); } else { log('nested else') 6 | } } 7 | else if (baz==null) 8 | { 9 | // else if 10 | log('elseif'); 11 | }else{ 12 | // else 13 | log('else'); 14 | // should keep the 2 empty lines 15 | 16 | 17 | } 18 | 19 | if( singleLine )singleLine(); 20 | 21 | 22 | // it's a trap! 23 | if (asi && noBraces) 24 | dolor() 25 | else 26 | amet(); 27 | 28 | -------------------------------------------------------------------------------- /lib/helpers.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | exports.shouldIndentChild = shouldIndentChild; 4 | function shouldIndentChild(parent, child, opts) { 5 | // this will avoid indenting objects/arrays/functions twice if they 6 | // are on left/right of a BinaryExpression, LogicalExpression or 7 | // UnaryExpression 8 | if (!child || !opts[parent.type + '.' + child.type]) { 9 | return false; 10 | } 11 | 12 | var left = child.left; 13 | var right = child.right; 14 | return !right || (!opts[right.type] && !opts[left.type]); 15 | } 16 | -------------------------------------------------------------------------------- /lib/hooks/ObjectPattern.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var limit = require('../limit'); 4 | var tk = require('rocambole-token'); 5 | 6 | exports.format = function ObjectPattern(node) { 7 | limit.around(node.startToken, 'ObjectPatternOpeningBrace'); 8 | limit.around(node.endToken, 'ObjectPatternClosingBrace'); 9 | 10 | node.properties.forEach(function(prop) { 11 | var comma = tk.findNext(prop.endToken, [',', '}']); 12 | if (comma.value === ',') { 13 | limit.around(comma, 'ObjectPatternComma'); 14 | } 15 | }); 16 | }; 17 | -------------------------------------------------------------------------------- /test/compare/default/iife-in.js: -------------------------------------------------------------------------------- 1 | (function(i){ function h(a,b,c,d,e){this._listener=b;this._isOnce=c;this.context=d;this._signal=a;this._priority=e||0}i.h=h;}(this)); 2 | 3 | 4 | // issue #191 5 | var data = { 6 | items: (function() { 7 | return [1, 2, 3, 4]; 8 | }()), 9 | foo: true 10 | }; 11 | 12 | // issue #223 13 | ( function() { 14 | var x = 1; 15 | foo(bar(), baz()); 16 | }() ); 17 | 18 | // issue #250 19 | ( function( $ ) { 20 | x; 21 | }( jQuery ) ); 22 | 23 | ;!function( x ) { 24 | console.log( x ) 25 | }( 'bar' ) 26 | -------------------------------------------------------------------------------- /test/compare/custom/for_statement-in.js: -------------------------------------------------------------------------------- 1 | for (i=0; i 0; --j ) { 17 | x(); 18 | } 19 | } 20 | 21 | for(;; ) { 22 | x(); 23 | } 24 | 25 | function foo() { 26 | for (var c = this._bindings.length, d;c--;) 27 | x += 1; 28 | return -1; 29 | } 30 | 31 | for ( i = 0;i< 10;i++) foo(); 32 | for (i=10; i < 10; i++ ) 33 | bar(); 34 | -------------------------------------------------------------------------------- /test/compare/custom/call_expression-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "indent" : { 3 | "MemberExpression" : 0 4 | }, 5 | "lineBreak": { 6 | "before": { 7 | "ArgumentComma" : 0, 8 | "CallExpression": ">=1" 9 | }, 10 | "after": { 11 | "ArgumentComma" : 0, 12 | "CallExpression": ">=1" 13 | } 14 | }, 15 | "whiteSpace" : { 16 | "before" : { 17 | "ArgumentList" : 1, 18 | "ArgumentComma" : 1 19 | }, 20 | "after" : { 21 | "ArgumentList" : 1, 22 | "ArgumentComma" : 0 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/compare/custom/if_statement_spacy-out.js: -------------------------------------------------------------------------------- 1 | if ( true ) { 2 | doStuff() 3 | } 4 | 5 | if ( foo || bar ) { 6 | if ( bar === 'bar' ) { 7 | // nested 8 | log('nested if'); 9 | } else { 10 | log('nested else') 11 | } 12 | } else if ( baz == null ) { 13 | // else if 14 | log('elseif'); 15 | } else { 16 | // else 17 | log('else'); 18 | // should keep the 2 empty lines 19 | 20 | 21 | } 22 | 23 | if ( singleLine ) singleLine(); 24 | 25 | 26 | // it's a trap! 27 | if ( asi && noBraces ) 28 | dolor() 29 | else 30 | amet(); 31 | 32 | -------------------------------------------------------------------------------- /test/compare/default/flow-in.js: -------------------------------------------------------------------------------- 1 | /** 2 | * important! this file is only to ensure we parse files with Flow annotation 3 | * properly. The formatting of typeAnnotation should be handled by an external 4 | * plugin since not all users will require this feature and implementation is 5 | * pretty complex. 6 | * @flow 7 | */ 8 | function foo(a: string, b: number): void { 9 | return a + String(b); 10 | } 11 | 12 | var x: boolean = someBool; 13 | 14 | class Bar { 15 | y: string; 16 | someMethod(a: number): string { 17 | return a * 2; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/compare/default/flow-out.js: -------------------------------------------------------------------------------- 1 | /** 2 | * important! this file is only to ensure we parse files with Flow annotation 3 | * properly. The formatting of typeAnnotation should be handled by an external 4 | * plugin since not all users will require this feature and implementation is 5 | * pretty complex. 6 | * @flow 7 | */ 8 | function foo(a: string, b: number): void { 9 | return a + String(b); 10 | } 11 | 12 | var x: boolean = someBool; 13 | 14 | class Bar { 15 | y: string; 16 | someMethod(a: number): string { 17 | return a * 2; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/compare/custom/call_expression-in.js: -------------------------------------------------------------------------------- 1 | foo(); 2 | 3 | bar(1,'dolor');ipsum(3,{amet:true},'foo'); 4 | 5 | dolor=foo(2) 6 | 7 | // should remove line breaks 8 | foo(a,b, 9 | c,d) 10 | 11 | 12 | // it should indent chained calls if there is a line break between each call 13 | foo.bar() 14 | .ipsum() 15 | .dolor(); 16 | 17 | function foo() { 18 | dolor 19 | .amet() 20 | .maecennas(); 21 | } 22 | 23 | returned.promise().done(foo) 24 | .done(newDefer.resolve) 25 | .fail(newDefer.reject) 26 | .progress(newDefer.notify); 27 | 28 | -------------------------------------------------------------------------------- /test/plugin/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // IMPORTANT: run `npm rm esformatter-test-plugin && npm i test/plugin` every 4 | // time you update this file! 5 | 6 | exports.setOptions = function(opts, esformatter) { 7 | opts.foo = 'bar'; 8 | opts.bar = 123; 9 | // makes sure we are able to read default values and edit it 10 | opts.indent.ArrayExpression += 2; 11 | this.opts = opts; 12 | this.esformatter = esformatter; 13 | }; 14 | 15 | exports.tokenBefore = function(token) { 16 | if (token.value === 'true') { 17 | token.value = 'false'; 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /test/compare/custom/call_expression-out.js: -------------------------------------------------------------------------------- 1 | foo(); 2 | 3 | bar( 1 ,'dolor' ); 4 | ipsum( 3 ,{ 5 | amet: true 6 | } ,'foo' ); 7 | 8 | dolor = foo( 2 ) 9 | 10 | // should remove line breaks 11 | foo( a ,b ,c ,d ) 12 | 13 | 14 | // it should indent chained calls if there is a line break between each call 15 | foo.bar() 16 | .ipsum() 17 | .dolor(); 18 | 19 | function foo() { 20 | dolor 21 | .amet() 22 | .maecennas(); 23 | } 24 | 25 | returned.promise().done( foo ) 26 | .done( newDefer.resolve ) 27 | .fail( newDefer.reject ) 28 | .progress( newDefer.notify ); 29 | 30 | -------------------------------------------------------------------------------- /test/compare/custom/for_statement-out.js: -------------------------------------------------------------------------------- 1 | for ( i = 0; i < n; ++i ) { 2 | x(); 3 | } 4 | 5 | for ( ; i < n; ++i ) { 6 | x(); 7 | } 8 | 9 | for ( ;; ++i ) { 10 | x(); 11 | } 12 | 13 | for ( i = 0;; ) { 14 | x(); 15 | } 16 | 17 | for ( ; i < n; ++i ) { 18 | for ( ; j > 0; --j ) { 19 | x(); 20 | } 21 | } 22 | 23 | for ( ;; ) { 24 | x(); 25 | } 26 | 27 | function foo() { 28 | for ( var c = this._bindings.length, d; c--; ) 29 | x += 1; 30 | return -1; 31 | } 32 | 33 | for ( i = 0; i < 10; i++ ) foo(); 34 | for ( i = 10; i < 10; i++ ) 35 | bar(); 36 | -------------------------------------------------------------------------------- /test/compare/custom/commented_config-config.json: -------------------------------------------------------------------------------- 1 | /* 2 | * This is an example of comments used on a config.json file 3 | */ 4 | 5 | { 6 | // In this style guide we'll have curly brackets on next line :) 7 | "lineBreak" : { 8 | "before" : { 9 | "IfStatementOpeningBrace" : 1 10 | } 11 | }, 12 | 13 | // No whitespace between if statement and parenthesis 14 | "whiteSpace" : { 15 | "before" : { 16 | "IfStatementConditionalOpening" : 0, 17 | "IfStatementConditionalClosing" : 0 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/hooks/ImportDeclaration.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _br = require('rocambole-linebreak'); 4 | var _tk = require('rocambole-token'); 5 | var _ws = require('rocambole-whitespace'); 6 | 7 | exports.format = function ImportDeclaration(node) { 8 | _br.limitAfter(node.startToken, 0); 9 | _ws.limitAfter(node.startToken, 1); 10 | 11 | // node.specifiers is actually handled by the ImportSpecifier hook! 12 | 13 | if (!node.specifiers.length) return; 14 | 15 | var fromKeyword = _tk.findPrev(node.endToken, 'from'); 16 | _br.limit(fromKeyword, 0); 17 | _ws.limit(fromKeyword, 1); 18 | }; 19 | -------------------------------------------------------------------------------- /test/compare/custom/object_expression-3-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lineBreak" : { 3 | "before" : { 4 | "ObjectExpressionOpeningBrace": -1, 5 | "ObjectExpressionClosingBrace": -1, 6 | "Property": -1 7 | }, 8 | 9 | "after": { 10 | "ObjectExpressionOpeningBrace": -1, 11 | "ObjectExpressionClosingBrace": -1, 12 | "Property": -1 13 | } 14 | }, 15 | 16 | "whiteSpace" : { 17 | "before": { 18 | "ObjectExpressionClosingBrace": 1 19 | }, 20 | "after" : { 21 | "ObjectExpressionOpeningBrace": 1, 22 | "PropertyValue": -1 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/compare/default/iife-out.js: -------------------------------------------------------------------------------- 1 | (function(i) { 2 | function h(a, b, c, d, e) { 3 | this._listener = b; 4 | this._isOnce = c; 5 | this.context = d; 6 | this._signal = a; 7 | this._priority = e || 0 8 | } 9 | i.h = h; 10 | }(this)); 11 | 12 | 13 | // issue #191 14 | var data = { 15 | items: (function() { 16 | return [1, 2, 3, 4]; 17 | }()), 18 | foo: true 19 | }; 20 | 21 | // issue #223 22 | (function() { 23 | var x = 1; 24 | foo(bar(), baz()); 25 | }()); 26 | 27 | // issue #250 28 | (function($) { 29 | x; 30 | }(jQuery)); 31 | 32 | ;!function(x) { 33 | console.log(x) 34 | }('bar') 35 | -------------------------------------------------------------------------------- /test/compare/custom/function-expression-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lineBreak" : { 3 | "after": { 4 | "ParameterComma": 0 5 | } 6 | }, 7 | "whiteSpace" : { 8 | "before" : { 9 | "FunctionName" : 1, 10 | "FunctionExpressionOpeningBrace" : 1, 11 | "FunctionExpressionClosingBrace" : 1, 12 | "FunctionGeneratorAsterisk" : 1 13 | }, 14 | "after" : { 15 | "FunctionReservedWord": 1, 16 | "FunctionName" : 1, 17 | "FunctionExpressionOpeningBrace" : 1, 18 | "FunctionExpressionClosingBrace" : 1 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/compare/custom/switch_statement-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "indent" : { 3 | "SwitchStatement" : 0, 4 | "SwitchCase": 1 5 | }, 6 | "whiteSpace" : { 7 | "before" : { 8 | "SwitchDiscriminantClosing" : 1 9 | }, 10 | "after" : { 11 | "SwitchDiscriminantOpening" : 1 12 | } 13 | }, 14 | "lineBreak": { 15 | "before": { 16 | "SwitchOpeningBrace": 1, 17 | "SwitchClosingBrace": 1 18 | }, 19 | "after": { 20 | "BreakKeyword": 2, 21 | "SwitchOpeningBrace": 1, 22 | "SwitchClosingBrace": ">= 0" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/compare/default/while_statement-out.js: -------------------------------------------------------------------------------- 1 | // no parens and asi 2 | while (cur = items[i++]) log(cur.name); 3 | 4 | // wrong indent and line breaks 5 | while ( 6 | ++n < 7 | 10 8 | ) { 9 | log(n) 10 | } 11 | 12 | // no body 13 | while (foo()); 14 | 15 | // break before open curly brace and lots of spaces 16 | while (true) { 17 | // comment inside 18 | foo(); 19 | } 20 | 21 | while (n--) { 22 | // nested 23 | while (i++) { 24 | // moar nested 25 | while (z++ < 0) { 26 | // inception 27 | foo(); 28 | while (j++) { 29 | // deeper 30 | bar(); 31 | } 32 | } 33 | } 34 | } 35 | 36 | 37 | // no body #2 38 | while (true); 39 | 40 | -------------------------------------------------------------------------------- /test/compare/custom/for_in_statement-in.js: -------------------------------------------------------------------------------- 1 | for(key in obj){doFoo(obj[key]);} 2 | // we do not remove line breaks! (we assume user knows what he is doing) 3 | for( key 4 | in obj )doFoo(obj[key]); 5 | 6 | for(var k in o){ 7 | console.log(k, o[k]); 8 | } 9 | 10 | for(key in obj ){ 11 | for(prop in obj[key]) { 12 | //indent 13 | console.log(prop) 14 | } 15 | } 16 | 17 | // issue #13 : ForInStatement should not mess with inline object indent 18 | function iss13() { 19 | for (i in {submit : true, change : true, focusin : true}) { 20 | console.log(i); 21 | } 22 | } 23 | 24 | // line breaks and weird spaces 25 | for (key in obj) 26 | 27 | { 28 | doFoo(obj[key]); 29 | } 30 | -------------------------------------------------------------------------------- /test/compare/custom/for_of_statement-in.js: -------------------------------------------------------------------------------- 1 | for(key of obj){doFoo(obj[key]);} 2 | // we do not remove line breaks! (we assume user knows what he is doing) 3 | for( key 4 | of obj )doFoo(obj[key]); 5 | 6 | for(var k of o){ 7 | console.log(k, o[k]); 8 | } 9 | 10 | for(key of obj ){ 11 | for(prop of obj[key]) { 12 | //indent 13 | console.log(prop) 14 | } 15 | } 16 | 17 | // issue #13 : ForOfStatement should not mess with inline object indent 18 | function iss13() { 19 | for (i of {submit : true, change : true, focusin : true}) { 20 | console.log(i); 21 | } 22 | } 23 | 24 | // line breaks and weird spaces 25 | for (key of obj) 26 | 27 | { 28 | doFoo(obj[key]); 29 | } 30 | -------------------------------------------------------------------------------- /lib/hooks/ExportNamedDeclaration.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _br = require('rocambole-linebreak'); 4 | var _tk = require('rocambole-token'); 5 | var _ws = require('rocambole-whitespace'); 6 | 7 | exports.format = function ExportNamedDeclaration(node) { 8 | _br.limitAfter(node.startToken, 0); 9 | _ws.limitAfter(node.startToken, 1); 10 | 11 | // node.specifiers is actually handled by the ExportSpecifier hook! 12 | 13 | if (!node.specifiers.length) return; 14 | 15 | var fromKeyword = _tk.findPrev(node.endToken, 'from'); 16 | if (fromKeyword) { 17 | // safeguard against `export { foo, bar };` (no "from") 18 | _br.limit(fromKeyword, 0); 19 | _ws.limit(fromKeyword, 1); 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /test/compare/default/binary_expression-in.js: -------------------------------------------------------------------------------- 1 | 1.33>>>0 2 | foo >> 3 ; 3 | 2+ 2 4 | 3 * 1; 5 | 3<<1 6 | 12 | 255 7 | 12^ 255 8 | ;(++n<10); 9 | 10 | // trailing 11 | 27&64 ; 12 | 15 % 5 13 | 14 | // asi and ExpressionStatement 15 | foo>bar 16 | a < b 17 | ;(a==b); 18 | ( a === b ); 19 | a<= b 20 | 3.25 >=b 21 | 22 | // issue #212 23 | var str = '' + 24 | v1 + 25 | 'x' + 26 | // ~~(xx.time/60) + 27 | xx.time + 28 | 'min'; 29 | 30 | msg = 'lorem' + 31 | 'ipsum' + 32 | 'dolor' + 33 | // sit 34 | 'amet' 35 | 36 | bar( 37 | 123 / 38 | 456 * 39 | 0.75 ^ 40 | 255 | 41 | 98 << 42 | 1 - 43 | 42 44 | ); 45 | 46 | log("foo" + 47 | "bar" 48 | ); 49 | -------------------------------------------------------------------------------- /lib/hooks/BinaryExpression.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _tk = require('rocambole-token'); 4 | var _ws = require('rocambole-whitespace'); 5 | 6 | 7 | exports.format = function BinaryExpression(node) { 8 | var operator = _tk.findNext(node.left.endToken, node.operator); 9 | _ws.limit(operator, 'BinaryExpressionOperator'); 10 | }; 11 | 12 | exports.getIndentEdges = function(node) { 13 | // we only add indent for the top most BinaryExpression (in case we have 14 | // multiple operations in a row) 15 | if (node.parent.type === 'BinaryExpression') { 16 | return; 17 | } 18 | 19 | return { 20 | startToken: node.startToken.next, 21 | endToken: node.endToken.next || node.endToken 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /test/compare/default/binary_expression-out.js: -------------------------------------------------------------------------------- 1 | 1.33 >>> 0 2 | foo >> 3; 3 | 2 + 2 4 | 3 * 1; 5 | 3 << 1 6 | 12 | 255 7 | 12 ^ 255 8 | ;(++n < 10); 9 | 10 | // trailing 11 | 27 & 64; 12 | 15 % 5 13 | 14 | // asi and ExpressionStatement 15 | foo > bar 16 | a < b 17 | ;(a == b); 18 | (a === b); 19 | a <= b 20 | 3.25 >= b 21 | 22 | // issue #212 23 | var str = '' + 24 | v1 + 25 | 'x' + 26 | // ~~(xx.time/60) + 27 | xx.time + 28 | 'min'; 29 | 30 | msg = 'lorem' + 31 | 'ipsum' + 32 | 'dolor' + 33 | // sit 34 | 'amet' 35 | 36 | bar( 37 | 123 / 38 | 456 * 39 | 0.75 ^ 40 | 255 | 41 | 98 << 42 | 1 - 43 | 42 44 | ); 45 | 46 | log("foo" + 47 | "bar" 48 | ); 49 | -------------------------------------------------------------------------------- /test/compare/default/logical_expression-in.js: -------------------------------------------------------------------------------- 1 | a||b 2 | a || foo; 3 | foo&&bar 4 | ;(a||b); 5 | ( a&&b&&c ); 6 | 7 | 8 | // expressions 9 | ;(a&&b) ||foo&&bar 10 | ;((a&&b)||c)||d 11 | 12 | 13 | // test line break and indent 14 | if (true) { 15 | var b;this.foo&&this.bar(); 16 | } 17 | 18 | (foo || bar); (dolor || amet); 19 | 20 | foo = dolor || 21 | amet && 22 | bar 23 | 24 | var foo = dolor && 25 | amet || 26 | maecennas 27 | 28 | var foo, 29 | bar = x && 30 | ( a || b ); 31 | 32 | function x() { 33 | return (x || y) && 34 | 35 | // comment 36 | call(); 37 | } 38 | 39 | // issue #380 40 | let property = property || { 41 | name: '111' 42 | } 43 | prop = prop || { 44 | foo: '111' 45 | } 46 | -------------------------------------------------------------------------------- /test/compare/custom/comment_group-in.js: -------------------------------------------------------------------------------- 1 | // this is a comment block 2 | // all the lines are considered 3 | // as a single "block" and we can 4 | // add linebreaks before/after 5 | // the whole block 6 | var foo = { 7 | // Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 8 | // tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim 9 | // veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea 10 | // commodo consequat. Duis aute irure dolor in reprehenderit in voluptate 11 | // velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat 12 | // cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id 13 | // est laborum. 14 | lorem: "ipsum" 15 | }; 16 | -------------------------------------------------------------------------------- /test/compare/custom/for_in_statement-out.js: -------------------------------------------------------------------------------- 1 | for ( key in obj ) 2 | { 3 | doFoo(obj[key]); 4 | } 5 | // we do not remove line breaks! (we assume user knows what he is doing) 6 | for ( key 7 | in obj ) doFoo(obj[key]); 8 | 9 | for ( var k in o ) 10 | { 11 | console.log(k, o[k]); 12 | } 13 | 14 | for ( key in obj ) 15 | { 16 | for ( prop in obj[key] ) 17 | { 18 | //indent 19 | console.log(prop) 20 | } 21 | } 22 | 23 | // issue #13 : ForInStatement should not mess with inline object indent 24 | function iss13() { 25 | for ( i in {submit: true, change: true, focusin: true} ) 26 | { 27 | console.log(i); 28 | } 29 | } 30 | 31 | // line breaks and weird spaces 32 | for ( key in obj ) 33 | { 34 | doFoo(obj[key]); 35 | } 36 | -------------------------------------------------------------------------------- /test/compare/custom/for_of_statement-out.js: -------------------------------------------------------------------------------- 1 | for ( key of obj ) 2 | { 3 | doFoo(obj[key]); 4 | } 5 | // we do not remove line breaks! (we assume user knows what he is doing) 6 | for ( key 7 | of obj ) doFoo(obj[key]); 8 | 9 | for ( var k of o ) 10 | { 11 | console.log(k, o[k]); 12 | } 13 | 14 | for ( key of obj ) 15 | { 16 | for ( prop of obj[key] ) 17 | { 18 | //indent 19 | console.log(prop) 20 | } 21 | } 22 | 23 | // issue #13 : ForOfStatement should not mess with inline object indent 24 | function iss13() { 25 | for ( i of {submit: true, change: true, focusin: true} ) 26 | { 27 | console.log(i); 28 | } 29 | } 30 | 31 | // line breaks and weird spaces 32 | for ( key of obj ) 33 | { 34 | doFoo(obj[key]); 35 | } 36 | -------------------------------------------------------------------------------- /test/compare/custom/switch_statement-out.js: -------------------------------------------------------------------------------- 1 | switch ( event.keyCode ) 2 | { 3 | case $.ui.keyCode.ENTER: 4 | case $.ui.keyCode.SPACE: 5 | case $.ui.keyCode.DOWN_ARROW: 6 | // line comment 7 | z(); 8 | break 9 | 10 | case $.ui.keyCode.ESCAPE: 11 | y(); 12 | break; 13 | 14 | default: 15 | x(); 16 | } 17 | 18 | switch ( event.keyCode ) 19 | { 20 | case $.ui.keyCode.ENTER: 21 | whatever = 'nothing'; 22 | break 23 | 24 | case $.ui.keyCode.ESCAPE: 25 | whatever = 'something'; 26 | break; 27 | 28 | default: 29 | x(); 30 | } 31 | 32 | call(function() { 33 | switch ( fruit ) 34 | { 35 | case Fruit.APPLE: 36 | // line comment 37 | exotic(); 38 | break; 39 | 40 | default: 41 | unknown(); 42 | } 43 | }); 44 | -------------------------------------------------------------------------------- /test/compare/default/logical_expression-out.js: -------------------------------------------------------------------------------- 1 | a || b 2 | a || foo; 3 | foo && bar 4 | ;(a || b); 5 | (a && b && c); 6 | 7 | 8 | // expressions 9 | ;(a && b) || foo && bar 10 | ;((a && b) || c) || d 11 | 12 | 13 | // test line break and indent 14 | if (true) { 15 | var b; 16 | this.foo && this.bar(); 17 | } 18 | 19 | (foo || bar); (dolor || amet); 20 | 21 | foo = dolor || 22 | amet && 23 | bar 24 | 25 | var foo = dolor && 26 | amet || 27 | maecennas 28 | 29 | var foo, 30 | bar = x && 31 | (a || b); 32 | 33 | function x() { 34 | return (x || y) && 35 | 36 | // comment 37 | call(); 38 | } 39 | 40 | // issue #380 41 | let property = property || { 42 | name: '111' 43 | } 44 | prop = prop || { 45 | foo: '111' 46 | } 47 | -------------------------------------------------------------------------------- /test/compare/default/while_statement-in.js: -------------------------------------------------------------------------------- 1 | // no parens and asi 2 | while(cur=items[i++]) log(cur.name); 3 | 4 | // wrong indent and line breaks 5 | while( 6 | ++n < 7 | 10 8 | ) { 9 | log(n) 10 | } 11 | 12 | // no body 13 | while ( foo() ); 14 | 15 | // break before open curly brace and lots of spaces 16 | while ( true ) 17 | { 18 | // comment inside 19 | foo(); 20 | } 21 | 22 | while (n--){ 23 | // nested 24 | while(i++){ 25 | // moar nested 26 | while(z++<0) { 27 | // inception 28 | foo(); 29 | while(j++) { 30 | // deeper 31 | bar(); 32 | } 33 | } 34 | } 35 | } 36 | 37 | 38 | // no body #2 39 | while (true ) 40 | ; 41 | 42 | -------------------------------------------------------------------------------- /lib/limit.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // limit amount of consecutive white spaces and line breaks adjacent to a given 4 | // token. 5 | 6 | var _br = require('rocambole-linebreak'); 7 | var _ws = require('rocambole-whitespace'); 8 | 9 | exports.before = limitBefore; 10 | function limitBefore(token, typeOrValue) { 11 | _br.limitBefore(token, typeOrValue); 12 | _ws.limitBefore(token, typeOrValue); 13 | } 14 | 15 | 16 | exports.after = limitAfter; 17 | function limitAfter(token, typeOrValue) { 18 | _br.limitAfter(token, typeOrValue); 19 | _ws.limitAfter(token, typeOrValue); 20 | } 21 | 22 | 23 | exports.around = limitAround; 24 | function limitAround(token, typeOrValue) { 25 | _br.limit(token, typeOrValue); 26 | _ws.limit(token, typeOrValue); 27 | } 28 | -------------------------------------------------------------------------------- /test/compare/custom/comment_group-out.js: -------------------------------------------------------------------------------- 1 | // this is a comment block 2 | // all the lines are considered 3 | // as a single "block" and we can 4 | // add linebreaks before/after 5 | // the whole block 6 | 7 | var foo = { 8 | 9 | // Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 10 | // tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim 11 | // veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea 12 | // commodo consequat. Duis aute irure dolor in reprehenderit in voluptate 13 | // velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat 14 | // cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id 15 | // est laborum. 16 | 17 | lorem: "ipsum" 18 | }; 19 | -------------------------------------------------------------------------------- /test/compare/default/arrow_function_expression-out.js: -------------------------------------------------------------------------------- 1 | arr.map(a => a * 2); 2 | arr.map(b => { 3 | return b * 2; 4 | }); 5 | arr.map((c, i) => { 6 | return c * i; 7 | }); 8 | arr.map(d => { 9 | return d * 2; 10 | }); 11 | arr.map((e, f, g) => e * f - g); 12 | 13 | // default params (#285) 14 | let defaultParams = (x, y = 1, z = 2) => { 15 | return x + y + z; 16 | } 17 | 18 | // issue #393 19 | a = () => { 20 | test(() => { 21 | return 1 22 | }) 23 | test(() => { 24 | return 1 25 | }) 26 | } 27 | 28 | // issue #357 29 | const object = x => ({ 30 | x 31 | }); 32 | 33 | const retObject = x => { 34 | return { 35 | x 36 | }; 37 | } 38 | 39 | const array = x => [ 40 | x 41 | ]; 42 | 43 | const callWithObject = x => f({ 44 | x 45 | }); 46 | -------------------------------------------------------------------------------- /doc/cli.txt: -------------------------------------------------------------------------------- 1 | Usage: esformatter [options] [files...] 2 | 3 | Options: 4 | -v, --version Display the current version. 5 | -h, --help Display help and usage details. 6 | -c, --config Path to custom configuration file. 7 | -p, --preset Set style guide preset ("jquery", "default"). 8 | --plugins Comma separated list of plugins. 9 | -i Edit input files in place; use with care! 10 | --diff Check code style and output char diff. 11 | --diff-unified Check code style and output unified diff. 12 | --no-color Remove colors from diff (default if terminal doesn't 13 | support colors). 14 | --color Force colored diffs even if terminal doesn't support it. 15 | -------------------------------------------------------------------------------- /lib/esformatter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // non-destructive changes to EcmaScript code using an "enhanced" AST for the 4 | // process, it updates the tokens in place and add/remove spaces & line breaks 5 | // based on user settings. 6 | // not using any kind of code rewrite based on string concatenation to avoid 7 | // breaking the program correctness and/or undesired side-effects. 8 | 9 | var plugins = require('./plugins'); 10 | 11 | exports.diff = require('./diff'); 12 | exports.hooks = require('./hooks'); 13 | exports.format = require('./format'); 14 | exports.transform = require('./transform'); 15 | exports.rc = require('./options').getRc; 16 | exports.register = plugins.register; 17 | exports.unregister = plugins.unregister; 18 | exports.unregisterAll = plugins.unregisterAll; 19 | -------------------------------------------------------------------------------- /test/compare/default/for_statement-in.js: -------------------------------------------------------------------------------- 1 | for( 2 | var i=0, 3 | n=things.length; 4 | i< n; 5 | i += 1 6 | ){ 7 | // 1 8 | things[i]; 9 | } 10 | 11 | for (i= 0; i< n;++i) { // 2 12 | things[i]; } 13 | 14 | for (; i< n;++i) { foo(i); /* 3 */ } 15 | 16 | 17 | for (; i< n;++i) 18 | { 19 | // 4 20 | for(; j > 0; --j) { 21 | // 5 22 | things[i][j]; } 23 | } 24 | 25 | // 6 26 | for 27 | (;;) { 28 | things[i]; 29 | } 30 | 31 | 32 | // 7 : indent + no braces 33 | function foo() { 34 | for(var c=this._bindings.length,d;c--;)if (d = this._bindings[c], d._listener === a && d.context === b) return c;return -1} 35 | 36 | 37 | // 8: no {} 38 | for (i = 0; i < 10; i++) foo(i); 39 | for (i = 10; i < 10; i++) 40 | bar(i); 41 | 42 | -------------------------------------------------------------------------------- /test/compare/default/unary_expression-in.js: -------------------------------------------------------------------------------- 1 | !a 2 | !!foo 3 | !(foo); 4 | ;(!!foo) 5 | !( ! foo ); 6 | !!(!foo); 7 | 8 | -x; 9 | - y; 10 | 11 | ~ a; //bitwise NOT is unary 12 | 13 | // these are actually UpdateExpression 14 | ++ foo; 15 | foo ++; 16 | -- bar; 17 | bar --; 18 | 19 | // delete is a UnaryExpression 20 | delete foo.bar; delete bar.amet; 21 | 22 | // issue #347 23 | delete foo['bar']; delete bar['amet']; 24 | 25 | // need to check indent as well 26 | function fn() { 27 | !!(!foo); 28 | delete this.bar 29 | delete this.amet;delete this.ipsum; 30 | 31 | delete this['bar'] 32 | delete this['amet'];delete this['ipsum']; 33 | } 34 | 35 | typeof a === "number" ? x : y; 36 | 37 | var s = 'a string'; 38 | console.log(typeof s); 39 | 40 | void 0; 41 | -------------------------------------------------------------------------------- /test/compare/default/unary_expression-out.js: -------------------------------------------------------------------------------- 1 | !a 2 | !!foo 3 | !(foo); 4 | ;(!!foo) 5 | !(!foo); 6 | !!(!foo); 7 | 8 | -x; 9 | -y; 10 | 11 | ~a; //bitwise NOT is unary 12 | 13 | // these are actually UpdateExpression 14 | ++foo; 15 | foo++; 16 | --bar; 17 | bar--; 18 | 19 | // delete is a UnaryExpression 20 | delete foo.bar; 21 | delete bar.amet; 22 | 23 | // issue #347 24 | delete foo['bar']; 25 | delete bar['amet']; 26 | 27 | // need to check indent as well 28 | function fn() { 29 | !!(!foo); 30 | delete this.bar 31 | delete this.amet; 32 | delete this.ipsum; 33 | 34 | delete this['bar'] 35 | delete this['amet']; 36 | delete this['ipsum']; 37 | } 38 | 39 | typeof a === "number" ? x : y; 40 | 41 | var s = 'a string'; 42 | console.log(typeof s); 43 | 44 | void 0; 45 | -------------------------------------------------------------------------------- /test/compare/default/arrow_function_expression-in.js: -------------------------------------------------------------------------------- 1 | arr.map(a=>a*2); 2 | arr.map(b => {return b * 2;}); 3 | arr.map(( c,i )=>{ 4 | return c * i; 5 | }); 6 | arr.map(d => 7 | {return d * 2;}); 8 | arr.map( ( e , f , g) => e * f - g ); 9 | 10 | // default params (#285) 11 | let defaultParams = (x, y = 1, z = 2 ) => { 12 | return x + y + z; 13 | } 14 | 15 | // issue #393 16 | a = () => { 17 | test( () => { 18 | return 1 19 | }) 20 | test(() => { 21 | return 1 22 | }) 23 | } 24 | 25 | // issue #357 26 | const object = x => ({ 27 | x 28 | }); 29 | 30 | const retObject = x => { 31 | return { 32 | x 33 | }; 34 | } 35 | 36 | const array = x => [ 37 | x 38 | ]; 39 | 40 | const callWithObject = x => f({ 41 | x 42 | }); 43 | -------------------------------------------------------------------------------- /test/compare/custom/array_expression-2-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "whiteSpace" : { 3 | "before" : { 4 | "ArrayExpressionOpening" : 0, 5 | "ArrayExpressionClosing" : 1 6 | }, 7 | "after" : { 8 | "ArrayExpressionOpening" : 1, 9 | "ArrayExpressionClosing" : 0 10 | } 11 | }, 12 | "lineBreak" : { 13 | "before" : { 14 | "ArrayExpressionOpening" : ">=1", 15 | "ArrayExpressionClosing" : 1, 16 | "ArrayExpressionComma" : 1, 17 | "VariableDeclarationSemiColon" : -1 18 | }, 19 | "after" : { 20 | "ArrayExpressionOpening" : 1, 21 | "ArrayExpressionClosing" : 1, 22 | "ArrayExpressionComma" : 1 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/compare/default/for_statement-out.js: -------------------------------------------------------------------------------- 1 | for ( 2 | var i = 0, 3 | n = things.length; 4 | i < n; 5 | i += 1 6 | ) { 7 | // 1 8 | things[i]; 9 | } 10 | 11 | for (i = 0; i < n; ++i) { // 2 12 | things[i]; 13 | } 14 | 15 | for (; i < n; ++i) { 16 | foo(i); /* 3 */ 17 | } 18 | 19 | 20 | for (; i < n; ++i) { 21 | // 4 22 | for (; j > 0; --j) { 23 | // 5 24 | things[i][j]; 25 | } 26 | } 27 | 28 | // 6 29 | for (;;) { 30 | things[i]; 31 | } 32 | 33 | 34 | // 7 : indent + no braces 35 | function foo() { 36 | for (var c = this._bindings.length, d; c--;) 37 | if (d = this._bindings[c], d._listener === a && d.context === b) return c; 38 | return -1 39 | } 40 | 41 | 42 | // 8: no {} 43 | for (i = 0; i < 10; i++) foo(i); 44 | for (i = 10; i < 10; i++) 45 | bar(i); 46 | 47 | -------------------------------------------------------------------------------- /test/compare/custom/top-level-indent-exception-out.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | // top level block isn't indented 4 | var x = 123; 5 | 6 | setTimeout(function() { 7 | x(); 8 | }); 9 | 10 | }()); 11 | 12 | // don't mess up other code outside a function scope 13 | var x = { 14 | abc: 123 15 | }; 16 | 17 | module.exports = function() { 18 | 19 | var x = 123; 20 | 21 | }; 22 | 23 | (function(factory) { 24 | if (typeof define === "function" && define.amd) { 25 | // AMD. Register as an anonymous module. 26 | define([ 27 | "jquery", 28 | "./core", 29 | "./widget" 30 | ], factory); 31 | } else { 32 | // Browser globals 33 | factory(jQuery); 34 | } 35 | }(function($) { 36 | return $.widget("ui.accordion", { 37 | version: "@VERSION", 38 | options: {} 39 | }); 40 | })); 41 | -------------------------------------------------------------------------------- /test/compare/custom/array_expression-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "whiteSpace" : { 3 | "before" : { 4 | "ArrayExpressionOpening" : 0, 5 | "ArrayExpressionClosing" : 1, 6 | "ArrayExpressionComma" : 1 7 | }, 8 | "after" : { 9 | "ArrayExpressionOpening" : 1, 10 | "ArrayExpressionClosing" : 0, 11 | "ArrayExpressionComma" : 0 12 | } 13 | }, 14 | "lineBreak" : { 15 | "before" : { 16 | "ArrayExpressionOpening" : -1, 17 | "ArrayExpressionClosing" : -1, 18 | "ArrayExpressionComma" : -1 19 | }, 20 | "after" : { 21 | "ArrayExpressionOpening" : -1, 22 | "ArrayExpressionClosing" : -1, 23 | "ArrayExpressionComma" : -1 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/compare/custom/object_expression-in.js: -------------------------------------------------------------------------------- 1 | foo.bar.Baz( { 2 | method2: function () {}, prop : 'dolor amet' 3 | , prop2 : 123 4 | }); 5 | 6 | 7 | function foo(a){ amet(123, a, {flag:true}); } 8 | ipsum({flag:true}); 9 | ipsum({flag:true,other:false}); 10 | ipsum({flag:true,other:false},789,'bar'); 11 | 12 | 13 | var obj = {foo:"bar", 'lorem' : 123, 14 | dolor :new Date() 15 | , "re": /\w+/g} ; 16 | 17 | // ObjectEpression within CallExpression needs to indent comments 18 | declare({ 19 | // comment 20 | create: {} 21 | }); 22 | 23 | this.element 24 | .add() 25 | .set({ 26 | // line comment 27 | // one more 28 | prop: "value" 29 | }); 30 | 31 | define( name, { 32 | _create: function() { 33 | this.element 34 | .add() 35 | .set({ 36 | // line comment 37 | // one more 38 | prop: "value" 39 | }); 40 | } 41 | }); 42 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | ; EditorConfig is awesome: http://EditorConfig.org 2 | 3 | ; top-most EditorConfig file 4 | root = true 5 | 6 | ; Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | 13 | ; test files can have mized indent and there is no way to reset the value so we 14 | ; only add to files/folders that need it 15 | [lib/**] 16 | indent_style = space 17 | indent_size = 2 18 | 19 | [bin/*] 20 | indent_style = space 21 | indent_size = 2 22 | 23 | [test/*.js] 24 | indent_style = space 25 | indent_size = 2 26 | 27 | [package.json] 28 | indent_style = space 29 | indent_size = 2 30 | 31 | ; The test files can have mixed indent, tailing white space, etc... 32 | [test/compare/**] 33 | insert_final_newline = false 34 | trim_trailing_whitespace = false 35 | 36 | -------------------------------------------------------------------------------- /lib/hooks/UnaryExpression.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _br = require('rocambole-linebreak'); 4 | var _tk = require('rocambole-token'); 5 | var _ws = require('rocambole-whitespace'); 6 | 7 | 8 | exports.format = function UnaryExpression(node) { 9 | if (node.operator === 'delete') { 10 | _ws.limitAfter(node.startToken, 1); 11 | _br.limitBefore(node.startToken, 'DeleteOperator'); 12 | 13 | var endToken = node.endToken; 14 | if (_tk.isWs(endToken.next)) { 15 | _ws.limitAfter(endToken, 0); 16 | } 17 | if (_tk.isSemiColon(endToken.next)) { 18 | endToken = endToken.next; 19 | } 20 | _br.limitAfter(endToken, 'DeleteOperator'); 21 | } else if (node.operator === 'typeof' || node.operator === 'void') { 22 | _ws.limitAfter(node.startToken, 1); 23 | } else { 24 | _ws.limit(node.startToken, 'UnaryExpressionOperator'); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /lib/hooks/FunctionDeclaration.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _tk = require('rocambole-token'); 4 | var _ws = require('rocambole-whitespace'); 5 | var _limit = require('../limit'); 6 | var _params = require('./Params'); 7 | 8 | 9 | exports.format = function FunctionDeclaration(node) { 10 | if (node.id) { 11 | _limit.around(node.id.startToken, 'FunctionName'); 12 | } 13 | if (node.generator) { 14 | var genToken = _tk.findNextNonEmpty(node.startToken); 15 | _ws.limitBefore(genToken, 'FunctionGeneratorAsterisk'); 16 | } 17 | _params.format(node); 18 | _limit.around(node.body.startToken, 'FunctionDeclarationOpeningBrace'); 19 | _limit.around(node.body.endToken, 'FunctionDeclarationClosingBrace'); 20 | }; 21 | 22 | 23 | exports.getIndentEdges = function(node, opts) { 24 | return [ 25 | _params.getIndentEdges(node, opts), 26 | node.body 27 | ]; 28 | }; 29 | -------------------------------------------------------------------------------- /test/compare/custom/switch_statement-in.js: -------------------------------------------------------------------------------- 1 | switch ( event.keyCode ) { 2 | case $.ui.keyCode.ENTER : 3 | case $.ui.keyCode.SPACE: case $.ui.keyCode.DOWN_ARROW: 4 | // line comment 5 | z(); 6 | break 7 | case $.ui.keyCode.ESCAPE: 8 | y(); 9 | break; 10 | default: 11 | x(); 12 | } 13 | 14 | switch ( event.keyCode ) { 15 | case $.ui.keyCode.ENTER : 16 | whatever = 'nothing'; 17 | break 18 | case $.ui.keyCode.ESCAPE 19 | : 20 | whatever = 'something'; 21 | break; 22 | default: 23 | x(); 24 | } 25 | 26 | call(function(){ 27 | switch (fruit) { 28 | case Fruit.APPLE: 29 | // line comment 30 | exotic(); 31 | break; 32 | default: 33 | unknown(); 34 | } 35 | }); 36 | -------------------------------------------------------------------------------- /test/compare/custom/if_statement-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lineBreak" : { 3 | "before" : { 4 | "IfStatement": ">=1", 5 | "ElseStatement" : 1, 6 | "ElseIfStatement" : 1, 7 | "IfStatementOpeningBrace" : 1, 8 | "ElseStatementOpeningBrace" : 1, 9 | "ElseIfStatementOpeningBrace" : 1, 10 | "LineComment": -1 11 | }, 12 | "after": { 13 | "IfStatementOpeningBrace" : 1, 14 | "ElseStatementOpeningBrace" : 1 15 | } 16 | }, 17 | 18 | "whiteSpace" : { 19 | "before" : { 20 | "IfStatementConditionalOpening" : 0, 21 | "IfStatementConditionalClosing" : 0 22 | }, 23 | "after" : { 24 | "IfStatementConditionalOpening" : 0, 25 | "IfStatementConditionalClosing" : 1 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/hooks/SwitchStatement.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _tk = require('rocambole-token'); 4 | var _limit = require('../limit'); 5 | 6 | 7 | exports.format = function SwitchStatement(node) { 8 | var opening = _tk.findPrev(node.discriminant.startToken, '('); 9 | var closing = _tk.findNext(node.discriminant.endToken, ')'); 10 | var openingBrace = _tk.findNext(closing, '{'); 11 | var closingBrace = node.endToken; 12 | 13 | _limit.around(openingBrace, 'SwitchOpeningBrace'); 14 | _limit.around(closingBrace, 'SwitchClosingBrace'); 15 | _limit.around(opening, 'SwitchDiscriminantOpening'); 16 | _limit.around(closing, 'SwitchDiscriminantClosing'); 17 | 18 | // cases are handled by SwitchCase hook! 19 | 20 | }; 21 | 22 | 23 | exports.getIndentEdges = function(node) { 24 | return { 25 | startToken: _tk.findNext(node.discriminant.endToken, '{'), 26 | endToken: node.endToken 27 | }; 28 | }; 29 | -------------------------------------------------------------------------------- /test/compare/custom/top-level-indent-exception-in.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | // top level block isn't indented 4 | var x = 123; 5 | 6 | setTimeout(function() { 7 | x(); 8 | }); 9 | 10 | }()); 11 | 12 | // don't mess up other code outside a function scope 13 | var x = { 14 | abc: 123 15 | }; 16 | 17 | module.exports = function() { 18 | 19 | var x = 123; 20 | 21 | }; 22 | 23 | (function( factory ) { 24 | if ( typeof define === "function" && define.amd ) { 25 | // AMD. Register as an anonymous module. 26 | define([ 27 | "jquery", 28 | "./core", 29 | "./widget" 30 | ], factory ); 31 | } else { 32 | // Browser globals 33 | factory( jQuery ); 34 | } 35 | }(function( $ ) { 36 | return $.widget( "ui.accordion", { 37 | version: "@VERSION", 38 | options: {} 39 | }); 40 | })); 41 | -------------------------------------------------------------------------------- /test/compare/default/for_of_statement-out.js: -------------------------------------------------------------------------------- 1 | for (key of obj) { 2 | doFoo(obj[key]); 3 | } 4 | // we do not remove line breaks! (we assume user knows what he is doing) 5 | for (key 6 | of obj) doFoo(obj[key]); 7 | 8 | for (var k of o) { 9 | console.log(k, o[k]); 10 | } 11 | 12 | for (key of obj) { 13 | for (prop of obj[key]) { 14 | //indent 15 | console.log(prop) 16 | } 17 | } 18 | 19 | // issue #13 : ForInStatement should not mess with inline object indent 20 | function iss13() { 21 | for (i of {submit: true, change: true, focusin: true}) { 22 | console.log(i); 23 | } 24 | } 25 | 26 | // keep empty statement on one line 27 | var key; 28 | for (key of obj) {} 29 | 30 | 31 | 32 | 33 | 34 | 35 | for (key of obj) { 36 | // line breaks, weird spaces and multiple empty lines before 37 | doFoo(obj[key]); 38 | } 39 | 40 | // no {} 41 | for (key of obj) doFoo(obj[key]); 42 | for (k of o) 43 | fn(o[k]); 44 | -------------------------------------------------------------------------------- /test/compare/default/for_in_statement-out.js: -------------------------------------------------------------------------------- 1 | for (key in obj) { 2 | doFoo(obj[key]); 3 | } 4 | // we do not remove line breaks! (we assume user knows what he is doing) 5 | for (key 6 | in obj) doFoo(obj[key]); 7 | 8 | for (var k in o) { 9 | console.log(k, o[k]); 10 | } 11 | 12 | for (key in obj) { 13 | for (prop in obj[key]) { 14 | //indent 15 | console.log(prop) 16 | } 17 | } 18 | 19 | // issue #13 : ForInStatement should not mess with inline object indent 20 | function iss13() { 21 | for (i in {submit: true, change: true, focusin: true}) { 22 | console.log(i); 23 | } 24 | } 25 | 26 | // keep empty statement on one line 27 | var key; 28 | for (key in obj) {} 29 | 30 | 31 | 32 | 33 | 34 | 35 | for (key in obj) { 36 | // line breaks, weird spaces and multiple empty lines before 37 | doFoo(obj[key]); 38 | } 39 | 40 | // no {} 41 | for (key in obj) doFoo(obj[key]); 42 | for (k in o) 43 | fn(o[k]); 44 | 45 | -------------------------------------------------------------------------------- /test/compare/default/for_of_statement-in.js: -------------------------------------------------------------------------------- 1 | for(key of obj){doFoo(obj[key]);} 2 | // we do not remove line breaks! (we assume user knows what he is doing) 3 | for( key 4 | of obj )doFoo(obj[key]); 5 | 6 | for(var k of o){ 7 | console.log(k, o[k]); 8 | } 9 | 10 | for(key of obj){ 11 | for(prop of obj[key]) { 12 | //indent 13 | console.log(prop) 14 | } 15 | } 16 | 17 | // issue #13 : ForInStatement should not mess with inline object indent 18 | function iss13() { 19 | for (i of {submit : true, change : true, focusin : true}) { 20 | console.log(i); 21 | } 22 | } 23 | 24 | // keep empty statement on one line 25 | var key; 26 | for ( key of obj ) {} 27 | 28 | 29 | 30 | 31 | 32 | 33 | for (key of obj) 34 | 35 | { 36 | // line breaks, weird spaces and multiple empty lines before 37 | doFoo(obj[key]); 38 | } 39 | 40 | // no {} 41 | for ( key of obj ) doFoo(obj[key]); 42 | for ( k of o ) 43 | fn(o[k]); 44 | -------------------------------------------------------------------------------- /test/compare/default/for_in_statement-in.js: -------------------------------------------------------------------------------- 1 | for(key in obj){doFoo(obj[key]);} 2 | // we do not remove line breaks! (we assume user knows what he is doing) 3 | for( key 4 | in obj )doFoo(obj[key]); 5 | 6 | for(var k in o){ 7 | console.log(k, o[k]); 8 | } 9 | 10 | for(key in obj){ 11 | for(prop in obj[key]) { 12 | //indent 13 | console.log(prop) 14 | } 15 | } 16 | 17 | // issue #13 : ForInStatement should not mess with inline object indent 18 | function iss13() { 19 | for (i in {submit : true, change : true, focusin : true}) { 20 | console.log(i); 21 | } 22 | } 23 | 24 | // keep empty statement on one line 25 | var key; 26 | for ( key in obj ) {} 27 | 28 | 29 | 30 | 31 | 32 | 33 | for (key in obj) 34 | 35 | { 36 | // line breaks, weird spaces and multiple empty lines before 37 | doFoo(obj[key]); 38 | } 39 | 40 | // no {} 41 | for ( key in obj ) doFoo(obj[key]); 42 | for ( k in o ) 43 | fn(o[k]); 44 | 45 | -------------------------------------------------------------------------------- /lib/hooks/DoWhileStatement.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _tk = require('rocambole-token'); 4 | var _limit = require('../limit'); 5 | var _ws = require('rocambole-whitespace'); 6 | 7 | 8 | exports.format = function DoWhileStatement(node) { 9 | if (node.body.type === 'BlockStatement') { 10 | _limit.around(node.body.startToken, 'DoWhileStatementOpeningBrace'); 11 | _limit.around(node.body.endToken, 'DoWhileStatementClosingBrace'); 12 | } else { 13 | _ws.limitAfter(node.startToken, 1); 14 | } 15 | var whileKeyword = _tk.findPrev(node.test.startToken, 'while'); 16 | _ws.limit(whileKeyword, 1); 17 | }; 18 | 19 | 20 | exports.getIndentEdges = function(node) { 21 | return [ 22 | { // do 23 | startToken: node.startToken.next, 24 | endToken: node.body.endToken 25 | }, 26 | { // while 27 | startToken: _tk.findNext(node.body.endToken, '('), 28 | endToken: _tk.findPrev(node.endToken, ')') 29 | } 30 | ]; 31 | }; 32 | -------------------------------------------------------------------------------- /test/compare/custom/expression_parentheses-in.js: -------------------------------------------------------------------------------- 1 | ;(++n<10); 2 | ; (a==b); 3 | ( c === d ); 4 | x = (value / 10); 5 | if (r * (x+1)+(y+2)) { 6 | y = ("123"+"3456"); 7 | // parseInt() is the "catch" on this case 8 | z = ((q + w) / (parseInt('abc', 16) * (7) )) 9 | } 10 | 11 | 12 | // edge cases 13 | // ========== 14 | 15 | // not a bynary expression or a ExpressionStatement 16 | // VariableDeclaration > VariableDeclarator > [Identifier + Literal] 17 | var foo = (123); 18 | 19 | 20 | // SequenceExpression 21 | madness = (weird,stuff),(45,56) 22 | 23 | ;(bar()); 24 | (function(){})(); 25 | (function(){}()); 26 | 27 | function returnTest() { 28 | return (x > 1); 29 | } 30 | 31 | function returnTest2() { 32 | return ( y + 1 ); 33 | } 34 | 35 | function returnTest3(amount) { 36 | return amount + " result" + (amount > 1 ? "s" : ""); 37 | } 38 | 39 | function returnTest4() { 40 | return (a || b < 0) && y(); 41 | } 42 | 43 | 44 | fn((1 + 3) + 4); 45 | -------------------------------------------------------------------------------- /lib/hooks/CatchClause.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _tk = require('rocambole-token'); 4 | var _limit = require('../limit'); 5 | 6 | 7 | exports.format = function CatchClause(node) { 8 | _limit.around(node.startToken, 'CatchKeyword'); 9 | 10 | _limit.before(node.param.startToken, 'CatchParameterList'); 11 | _limit.after(node.param.endToken, 'CatchParameterList'); 12 | 13 | _limit.around(node.body.startToken, 'CatchOpeningBrace'); 14 | _limit.around(node.body.endToken, 'CatchClosingBrace'); 15 | 16 | // only remove line breaks if there are no comments inside. Ref #169 17 | if (!node.body.body.length && !containsCommentsInside(node.body)) { 18 | _tk.removeEmptyInBetween(node.body.startToken, node.body.endToken); 19 | } 20 | }; 21 | 22 | 23 | function containsCommentsInside(node) { 24 | return !!_tk.findInBetween(node.startToken, node.endToken, _tk.isComment); 25 | } 26 | 27 | exports.getIndentEdges = function(node) { 28 | return node.body; 29 | }; 30 | -------------------------------------------------------------------------------- /test/compare/custom/if_statement-in.js: -------------------------------------------------------------------------------- 1 | if(true){doStuff()} 2 | 3 | if( foo ||bar ){ if (bar === 'bar'){ 4 | // nested 5 | log('nested if'); } else { log('nested else') 6 | } } 7 | else if (baz==null) 8 | { 9 | // else if 10 | log('elseif'); 11 | }else{ 12 | // else 13 | log('else'); 14 | // should keep the 2 empty lines 15 | 16 | 17 | } 18 | 19 | if( singleLine )singleLine(); 20 | 21 | 22 | // it's a trap! 23 | if (asi && noBraces) 24 | dolor() 25 | else 26 | amet(); 27 | 28 | 29 | 30 | // issue #34 (break line comment into individual line) 31 | if ( window.DOMParser ) { // Standard 32 | tmp = new DOMParser(); 33 | xml = tmp.parseFromString( data , "text/xml" ); 34 | } else { // IE 35 | xml = new ActiveXObject( "Microsoft.XMLDOM" ); 36 | xml.async = "false"; 37 | xml.loadXML( data ); 38 | } 39 | 40 | 41 | // issue #196 42 | if (a) 43 | a(); // run a 44 | else if (b) 45 | b(); // run b 46 | else { 47 | c(); // run c 48 | } 49 | -------------------------------------------------------------------------------- /test/compare/custom/expression_parentheses-out.js: -------------------------------------------------------------------------------- 1 | ;( ++n < 10 ); 2 | ;( a == b ); 3 | ( c === d ); 4 | x = ( value / 10 ); 5 | if (r * ( x + 1 ) + ( y + 2 )) { 6 | y = ( "123" + "3456" ); 7 | // parseInt() is the "catch" on this case 8 | z = ( ( q + w ) / ( parseInt('abc', 16) * ( 7 ) ) ) 9 | } 10 | 11 | 12 | // edge cases 13 | // ========== 14 | 15 | // not a bynary expression or a ExpressionStatement 16 | // VariableDeclaration > VariableDeclarator > [Identifier + Literal] 17 | var foo = ( 123 ); 18 | 19 | 20 | // SequenceExpression 21 | madness = ( weird, stuff ), ( 45, 56 ) 22 | 23 | ;( bar() ); 24 | (function() {})(); 25 | (function() {}()); 26 | 27 | function returnTest() { 28 | return ( x > 1 ); 29 | } 30 | 31 | function returnTest2() { 32 | return ( y + 1 ); 33 | } 34 | 35 | function returnTest3(amount) { 36 | return amount + " result" + ( amount > 1 ? "s" : "" ); 37 | } 38 | 39 | function returnTest4() { 40 | return ( a || b < 0 ) && y(); 41 | } 42 | 43 | 44 | fn(( 1 + 3 ) + 4); 45 | -------------------------------------------------------------------------------- /test/compare/custom/basic_function_indent-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "indent" : { 3 | "FunctionDeclaration" : 0 4 | }, 5 | "lineBreak" : { 6 | "before" : { 7 | "FunctionDeclarationOpeningBrace" : 0, 8 | "FunctionDeclarationClosingBrace" : 0, 9 | "ReturnStatement" : 0 10 | }, 11 | "after" : { 12 | "FunctionDeclarationOpeningBrace" : 0, 13 | "FunctionDeclarationClosingBrace" : ">= 0" 14 | } 15 | }, 16 | "whiteSpace" : { 17 | "before" : { 18 | "ParameterList" : 1, 19 | "ParameterComma" : 0, 20 | "ParameterList" : 1, 21 | "FunctionDeclarationOpeningBrace" : 0, 22 | "FunctionDeclarationClosingBrace" : 1 23 | }, 24 | "after" : { 25 | "FunctionName" : 1, 26 | "ParameterComma" : 0, 27 | "ParameterList" : 1, 28 | "FunctionDeclarationOpeningBrace" : 1 29 | } 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /test/compare/custom/object_expression-out.js: -------------------------------------------------------------------------------- 1 | foo.bar.Baz({ 2 | method2 : function() {}, 3 | prop : 'dolor amet', 4 | prop2 : 123 5 | }); 6 | 7 | 8 | function foo(a) { 9 | amet(123, a, { 10 | flag : true 11 | }); 12 | } 13 | ipsum({ 14 | flag : true 15 | }); 16 | ipsum({ 17 | flag : true, 18 | other : false 19 | }); 20 | ipsum({ 21 | flag : true, 22 | other : false 23 | }, 789, 'bar'); 24 | 25 | 26 | var obj = { 27 | foo : "bar", 28 | 'lorem' : 123, 29 | dolor : new Date(), 30 | "re" : /\w+/g 31 | }; 32 | 33 | // ObjectEpression within CallExpression needs to indent comments 34 | declare({ 35 | // comment 36 | create : {} 37 | }); 38 | 39 | this.element 40 | .add() 41 | .set({ 42 | // line comment 43 | // one more 44 | prop : "value" 45 | }); 46 | 47 | define(name, { 48 | _create : function() { 49 | this.element 50 | .add() 51 | .set({ 52 | // line comment 53 | // one more 54 | prop : "value" 55 | }); 56 | } 57 | }); 58 | -------------------------------------------------------------------------------- /test/transform.spec.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true*/ 2 | /*global describe:false, it:false*/ 3 | "use strict"; 4 | 5 | var expect = require('chai').expect; 6 | 7 | var esformatter = require('../lib/esformatter'); 8 | var rocambole = require('rocambole'); 9 | 10 | 11 | // --- 12 | 13 | 14 | describe('esformatter.transform()', function() { 15 | 16 | it('should transform rocambole AST in place', function() { 17 | var inputAST = rocambole.parse('var foo = 123;'); 18 | var outputAST = esformatter.transform(inputAST); 19 | expect(outputAST).to.be.equal(inputAST); 20 | }); 21 | 22 | 23 | it('should allow options as second arg', function() { 24 | var inputAST = rocambole.parse('var foo = 123;'); 25 | var outputAST = esformatter.transform(inputAST, { 26 | whiteSpace: { 27 | after: { 28 | VariableName: 0 29 | }, 30 | before: { 31 | VariableValue: 0 32 | } 33 | } 34 | }); 35 | expect(outputAST.toString()).to.be.equal('var foo=123;'); 36 | }); 37 | 38 | 39 | }); 40 | -------------------------------------------------------------------------------- /lib/hooks/ClassDeclarationAndExpression.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // this file handles both ClassDeclaration and ClassExpression 4 | 5 | var tk = require('rocambole-token'); 6 | var ws = require('rocambole-whitespace'); 7 | var limit = require('../limit'); 8 | 9 | exports.format = function ClassDeclarationAndExpression(node) { 10 | var classKeyword = node.startToken; 11 | var opening = tk.findNext(node.startToken, '{'); 12 | var closing = node.endToken; 13 | // yes, we remove all the line breaks and limit to a single whitespace in 14 | // between the words since line breaks here would increase complexity 15 | tk.removeInBetween(classKeyword, opening, tk.isBr); 16 | ws.limitAfter(classKeyword, 1); 17 | var extendsKeyword = tk.findInBetween(classKeyword, opening, 'extends'); 18 | if (extendsKeyword) { 19 | ws.limit(extendsKeyword, 1); 20 | } 21 | 22 | limit.around(opening, 'ClassOpeningBrace'); 23 | limit.around(closing, 'ClassClosingBrace'); 24 | }; 25 | 26 | exports.getIndentEdges = function(node) { 27 | return node; 28 | }; 29 | -------------------------------------------------------------------------------- /test/compare/custom/if_statement-out.js: -------------------------------------------------------------------------------- 1 | if(true) 2 | { 3 | doStuff() 4 | } 5 | 6 | if(foo || bar) 7 | { 8 | if(bar === 'bar') 9 | { 10 | // nested 11 | log('nested if'); 12 | } 13 | else 14 | { 15 | log('nested else') 16 | } 17 | } 18 | else if(baz == null) 19 | { 20 | // else if 21 | log('elseif'); 22 | } 23 | else 24 | { 25 | // else 26 | log('else'); 27 | // should keep the 2 empty lines 28 | 29 | 30 | } 31 | 32 | if(singleLine) singleLine(); 33 | 34 | 35 | // it's a trap! 36 | if(asi && noBraces) 37 | dolor() 38 | else 39 | amet(); 40 | 41 | 42 | 43 | // issue #34 (break line comment into individual line) 44 | if(window.DOMParser) 45 | { // Standard 46 | tmp = new DOMParser(); 47 | xml = tmp.parseFromString(data, "text/xml"); 48 | } 49 | else 50 | { // IE 51 | xml = new ActiveXObject("Microsoft.XMLDOM"); 52 | xml.async = "false"; 53 | xml.loadXML(data); 54 | } 55 | 56 | 57 | // issue #196 58 | if(a) 59 | a(); // run a 60 | else if(b) 61 | b(); // run b 62 | else 63 | { 64 | c(); // run c 65 | } 66 | -------------------------------------------------------------------------------- /lib/hooks/LogicalExpression.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _br = require('rocambole-linebreak'); 4 | var _tk = require('rocambole-token'); 5 | var _ws = require('rocambole-whitespace'); 6 | 7 | 8 | exports.format = function LogicalExpression(node) { 9 | var operator = _tk.findNext(node.left.endToken, node.operator); 10 | _ws.limit(operator, 'LogicalExpressionOperator'); 11 | // revert line breaks since parenthesis might not be part of 12 | // node.startToken and node.endToken 13 | if (node.parent.type === 'ExpressionStatement') { 14 | var prev = _tk.findPrevNonEmpty(node.left.startToken); 15 | if (prev && prev.value === '(') { 16 | _br.limit(prev, 'ExpressionOpeningParentheses'); 17 | _ws.limit(prev, 'ExpressionOpeningParentheses'); 18 | node.startToken = prev; 19 | } 20 | var next = _tk.findNextNonEmpty(node.right.endToken); 21 | if (next && next.value === ')') { 22 | _br.limit(next, 'ExpressionClosingParentheses'); 23 | _ws.limit(next, 'ExpressionClosingParentheses'); 24 | node.endToken = next; 25 | } 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /test/compare/default/conditional_expression-in.js: -------------------------------------------------------------------------------- 1 | a?foo():bar(); 2 | 3 | b = (dolor!==amet) ? 'ipsum': 'dolor'; 4 | 5 | if(true){ 6 | // notice that we don't indent since "consequent" is on same line as "test" 7 | c = !a ?(!foo?d : function(){ 8 | return a; 9 | }):b; 10 | } 11 | 12 | // should break lines 13 | foo.a = true; a?foo() : bar() 14 | 15 | 16 | // from jquery 17 | x = function(num) { 18 | return num == null ? 19 | 20 | // Return a 'clean' array 21 | this.toArray() : 22 | 23 | // Return just the object 24 | (object); 25 | } 26 | 27 | function x() { 28 | x.test(y) ? 29 | a : 30 | b; 31 | } 32 | 33 | num == null ? 34 | 35 | // Return a 'clean' array 36 | this.toArray() : 37 | 38 | // Return just the object 39 | ( num < 0 ? this[ this.length + num ] : this[ num ] ); 40 | 41 | // issue #253 42 | var format = isSameDate(startDate, endDate) ? this._oneDayLabelFormat : 43 | 'event-multiple-day-duration'; 44 | 45 | // issue #380 46 | var foo = lorem ? 47 | ipsum : 48 | { 49 | dolor: 'sit' 50 | }; 51 | amet = qwert ? 52 | asd : 53 | { 54 | zxc: 'opi' 55 | }; 56 | -------------------------------------------------------------------------------- /test/compare/default/conditional_expression-out.js: -------------------------------------------------------------------------------- 1 | a ? foo() : bar(); 2 | 3 | b = (dolor !== amet) ? 'ipsum' : 'dolor'; 4 | 5 | if (true) { 6 | // notice that we don't indent since "consequent" is on same line as "test" 7 | c = !a ? (!foo ? d : function() { 8 | return a; 9 | }) : b; 10 | } 11 | 12 | // should break lines 13 | foo.a = true; 14 | a ? foo() : bar() 15 | 16 | 17 | // from jquery 18 | x = function(num) { 19 | return num == null ? 20 | 21 | // Return a 'clean' array 22 | this.toArray() : 23 | 24 | // Return just the object 25 | (object); 26 | } 27 | 28 | function x() { 29 | x.test(y) ? 30 | a : 31 | b; 32 | } 33 | 34 | num == null ? 35 | 36 | // Return a 'clean' array 37 | this.toArray() : 38 | 39 | // Return just the object 40 | (num < 0 ? this[this.length + num] : this[num]); 41 | 42 | // issue #253 43 | var format = isSameDate(startDate, endDate) ? this._oneDayLabelFormat : 44 | 'event-multiple-day-duration'; 45 | 46 | // issue #380 47 | var foo = lorem ? 48 | ipsum : 49 | { 50 | dolor: 'sit' 51 | }; 52 | amet = qwert ? 53 | asd : 54 | { 55 | zxc: 'opi' 56 | }; 57 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Miller Medeiros 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/compare/default/array_expression-in.js: -------------------------------------------------------------------------------- 1 | [ 2 | 3 | ]; 4 | 5 | [1,2,3]; 6 | 7 | [1,2,[3,4,[5,6,[7,8,9]]]]; 8 | 9 | function fn(){ 10 | return [4,5,[6, 7 , 8 ]]; 11 | } 12 | 13 | // issue #12 14 | var tuples = [ 15 | // comment test 16 | ["resolve", "done", "bla", "resolved"], 17 | ["reject", "fail", "lorem", "rejected"], 18 | [ 19 | ["lorem", "ipsum"] 20 | ], 21 | ["notify", "progress", "ipsum"] 22 | ]; 23 | 24 | var x, 25 | y = [ 26 | "a", 27 | "b", 28 | "c" 29 | ]; 30 | 31 | // rocambole issue with sparse arrays 32 | ;[,3,[,4]]; 33 | // sparse arrays indentation is tricky! 34 | ;[ 35 | , 36 | 3, 37 | [,, 38 | , 39 | 4 40 | ]]; 41 | ;[ 42 | , 43 | 3, 44 | [, 45 | 4 46 | ] 47 | ]; 48 | 49 | // issue #165 (MemberExpression) 50 | [ 51 | "grunt-contrib-concat", 52 | "grunt-contrib-watch", 53 | "grunt-contrib-jshint", 54 | "grunt-contrib-qunit" 55 | ].forEach(function( task ) { 56 | grunt.loadNpmTasks( task ); 57 | }); 58 | 59 | // issue #224 60 | var fa = [ { 61 | foo: 'bar', 62 | baz: 'yak' 63 | }, { 64 | foo: '1', 65 | baz: '2' 66 | } ]; 67 | 68 | // issue #239 69 | var data = [1, 70 | 2]; 71 | -------------------------------------------------------------------------------- /test/compare/default/array_expression-out.js: -------------------------------------------------------------------------------- 1 | []; 2 | 3 | [1, 2, 3]; 4 | 5 | [1, 2, [3, 4, [5, 6, [7, 8, 9]]]]; 6 | 7 | function fn() { 8 | return [4, 5, [6, 7, 8]]; 9 | } 10 | 11 | // issue #12 12 | var tuples = [ 13 | // comment test 14 | ["resolve", "done", "bla", "resolved"], 15 | ["reject", "fail", "lorem", "rejected"], 16 | [ 17 | ["lorem", "ipsum"] 18 | ], 19 | ["notify", "progress", "ipsum"] 20 | ]; 21 | 22 | var x, 23 | y = [ 24 | "a", 25 | "b", 26 | "c" 27 | ]; 28 | 29 | // rocambole issue with sparse arrays 30 | ;[, 3, [, 4]]; 31 | // sparse arrays indentation is tricky! 32 | ;[ 33 | , 34 | 3, 35 | [,, 36 | , 37 | 4 38 | ]]; 39 | ;[ 40 | , 41 | 3, 42 | [, 43 | 4 44 | ] 45 | ]; 46 | 47 | // issue #165 (MemberExpression) 48 | [ 49 | "grunt-contrib-concat", 50 | "grunt-contrib-watch", 51 | "grunt-contrib-jshint", 52 | "grunt-contrib-qunit" 53 | ].forEach(function(task) { 54 | grunt.loadNpmTasks(task); 55 | }); 56 | 57 | // issue #224 58 | var fa = [{ 59 | foo: 'bar', 60 | baz: 'yak' 61 | }, { 62 | foo: '1', 63 | baz: '2' 64 | }]; 65 | 66 | // issue #239 67 | var data = [1, 68 | 2]; 69 | -------------------------------------------------------------------------------- /test/compare/default/class_declaration-in.js: -------------------------------------------------------------------------------- 1 | // #286 2 | class Foo extends Bar { 3 | constructor (properties, name = 'lorem', ...extra) 4 | { 5 | this.properties = properties; 6 | this.name = name; 7 | this.extra = extra; 8 | } 9 | static 10 | log ( msg , level = 'log' ) { 11 | console[level](msg); 12 | } toObject () { return this.properties; } } class Foo extends Bar { 13 | // empty lines in between the MethodDefinition are valid/kept 14 | 15 | constructor(properties) { 16 | this.properties = properties; 17 | } 18 | 19 | get prop() { 20 | return 'getter'; 21 | } 22 | 23 | set prop(val) { 24 | Foo.log('setting: ', val) 25 | } 26 | 27 | static log(msg, level = 'log') { 28 | console[level]('[Foo]', msg); 29 | } 30 | 31 | toObject() { 32 | return this.properties; 33 | } 34 | 35 | } 36 | 37 | // Multi line declaration 38 | class 39 | Foo 40 | extends 41 | Bar 42 | { 43 | } 44 | // The value to be extended can be produced by an arbitrary expression. 45 | class Foo extends BarNamespace.Bar{} 46 | class Foo extends BarNamespace['Bar'].Bar["Bar"]('bar').Bar("bar", "bar"){} 47 | class Foo extends(BarNamespace.bar)(){} 48 | -------------------------------------------------------------------------------- /test/runner.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // we run mocha manually otherwise istanbul coverage won't work 4 | // run `npm test --coverage` to generate coverage report 5 | 6 | var Mocha = require('mocha'); 7 | 8 | 9 | // --- 10 | 11 | 12 | 13 | // to set these options run the test script like: 14 | // > BAIL=true GREP=array_expression REPORTER=dot npm test 15 | var opts = { 16 | ui: 'bdd', 17 | bail: !!(process.env.BAIL), 18 | reporter:( process.env.REPORTER || 'spec'), 19 | grep: process.env.GREP 20 | }; 21 | 22 | // we use the dot reporter on travis since it works better 23 | if (process.env.TRAVIS) { 24 | opts.reporter = 'dot'; 25 | } 26 | 27 | var m = new Mocha(opts); 28 | 29 | if (process.env.INVERT) { 30 | m.invert(); 31 | } 32 | 33 | 34 | m.addFile('test/format.spec.js'); 35 | m.addFile('test/transform.spec.js'); 36 | m.addFile('test/diff.spec.js'); 37 | m.addFile('test/cli.spec.js'); 38 | m.addFile('test/api.spec.js'); 39 | m.addFile('test/plugins.spec.js'); 40 | m.addFile('test/pipe.spec.js'); 41 | 42 | m.run(function(err) { 43 | var exitCode = err ? 1 : 0; 44 | if (err) console.log('failed tests: ' + err); 45 | process.exit(exitCode); 46 | }); 47 | 48 | -------------------------------------------------------------------------------- /test/compare/custom/array_expression-2-out.js: -------------------------------------------------------------------------------- 1 | []; 2 | 3 | [ 4 | 1 5 | , 6 | 2 7 | , 8 | 3 9 | ] 10 | ; 11 | 12 | [ 13 | 1 14 | , 15 | 2 16 | , 17 | [ 18 | 3 19 | , 20 | 4 21 | , 22 | [ 23 | 5 24 | , 25 | 6 26 | , 27 | [ 28 | 7 29 | , 30 | 8 31 | , 32 | 9 33 | ] 34 | ] 35 | ] 36 | ] 37 | ; 38 | 39 | function fn() { 40 | // IMPORTANT: we can't break lines here because of ASI!!! 41 | return [ 42 | 4 43 | , 44 | 5 45 | , 46 | [ 47 | 6 48 | , 49 | 7 50 | , 51 | 8 52 | ] 53 | ]; 54 | } 55 | 56 | // issue #12 57 | var tuples = [ 58 | // comment test 59 | [ 60 | "resolve" 61 | , 62 | "done" 63 | , 64 | "bla" 65 | , 66 | "resolved" 67 | ] 68 | , 69 | [ 70 | "reject" 71 | , 72 | "fail" 73 | , 74 | "lorem" 75 | , 76 | "rejected" 77 | ] 78 | , 79 | [ 80 | [ 81 | "lorem" 82 | , 83 | "ipsum" 84 | ] 85 | ] 86 | , 87 | [ 88 | "notify" 89 | , 90 | "progress" 91 | , 92 | "ipsum" 93 | ] 94 | ] 95 | ; 96 | -------------------------------------------------------------------------------- /test/compare/default/class_declaration-out.js: -------------------------------------------------------------------------------- 1 | // #286 2 | class Foo extends Bar { 3 | constructor(properties, name = 'lorem', ...extra) { 4 | this.properties = properties; 5 | this.name = name; 6 | this.extra = extra; 7 | } 8 | static log(msg, level = 'log') { 9 | console[level](msg); 10 | } 11 | toObject() { 12 | return this.properties; 13 | } 14 | } 15 | class Foo extends Bar { 16 | // empty lines in between the MethodDefinition are valid/kept 17 | 18 | constructor(properties) { 19 | this.properties = properties; 20 | } 21 | 22 | get prop() { 23 | return 'getter'; 24 | } 25 | 26 | set prop(val) { 27 | Foo.log('setting: ', val) 28 | } 29 | 30 | static log(msg, level = 'log') { 31 | console[level]('[Foo]', msg); 32 | } 33 | 34 | toObject() { 35 | return this.properties; 36 | } 37 | 38 | } 39 | 40 | // Multi line declaration 41 | class Foo extends Bar { 42 | } 43 | // The value to be extended can be produced by an arbitrary expression. 44 | class Foo extends BarNamespace.Bar { 45 | } 46 | class Foo extends BarNamespace['Bar'].Bar["Bar"]('bar').Bar("bar", "bar") { 47 | } 48 | class Foo extends (BarNamespace.bar)() { 49 | } 50 | -------------------------------------------------------------------------------- /lib/hooks/AssignmentExpression.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _tk = require('rocambole-token'); 4 | var _ws = require('rocambole-whitespace'); 5 | var _br = require('rocambole-linebreak'); 6 | var helpers = require('../helpers'); 7 | 8 | 9 | exports.format = function AssignmentExpression(node) { 10 | // can't use node.right.startToken since it might be surrounded by 11 | // a parenthesis (see #5) 12 | var operator = _tk.findNext(node.left.endToken, node.operator); 13 | _br.limit(operator, 'AssignmentOperator'); 14 | _ws.limit(operator, 'AssignmentOperator'); 15 | }; 16 | 17 | 18 | exports.getIndentEdges = function(node, opts) { 19 | var operator = _tk.findNext(node.left.endToken, node.operator); 20 | if (_tk.findInBetween(operator, node.right.startToken, _tk.isBr) || 21 | (helpers.shouldIndentChild(node, node.right, opts) && 22 | _tk.findInBetween(operator, node.right.endToken, _tk.isBr))) { 23 | // we only indent if assignment is on next line 24 | return { 25 | level: opts['AssignmentExpression.' + node.right.type], 26 | startToken: operator, 27 | endToken: node.endToken.type !== 'Punctuator' ? 28 | node.endToken.next : node.endToken 29 | }; 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /lib/diff.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var format = require('./format'); 4 | var disparity = require('disparity'); 5 | 6 | var hr = '==================================================================' + 7 | '=============='; 8 | 9 | // these headers make more sense in this context 10 | disparity.added = 'expected'; 11 | disparity.removed = 'actual'; 12 | 13 | exports.chars = chars; 14 | function chars(str, opts, fileName) { 15 | var result = disparity.chars(str, format(str, opts)); 16 | if (!result) { 17 | return ''; 18 | } 19 | // we add a line break at the end because it looks better 20 | return getHeader(fileName) + result + '\n'; 21 | } 22 | 23 | function getHeader(fileName) { 24 | return fileName ? cyan(fileName) + '\n' + cyan(hr) + '\n' : ''; 25 | } 26 | 27 | function cyan(str) { 28 | return '\u001b[36m' + str + '\u001b[39m'; 29 | } 30 | 31 | exports.unified = unified; 32 | function unified(str, opts, fileName) { 33 | return disparity.unified(str, format(str, opts), { 34 | paths: [fileName] 35 | }); 36 | } 37 | 38 | exports.unifiedNoColor = unifiedNoColor; 39 | function unifiedNoColor(str, opts, fileName) { 40 | return disparity.unifiedNoColor(str, format(str, opts), { 41 | paths: [fileName] 42 | }); 43 | } 44 | -------------------------------------------------------------------------------- /test/compare/default/comments-out.js: -------------------------------------------------------------------------------- 1 | // line comment, no indent 2 | 3 | /* 4 | * block comment, no indent 5 | */ 6 | if (true) { 7 | // line comment, 1 indent 8 | /** 9 | * block comment, 1 indent 10 | */ 11 | if (true) { 12 | // line comment, 2 indents 13 | /* 14 | * block comment, 2 indent 15 | */ 16 | if (true) { 17 | /* block single line, 3 indents */ 18 | /* 19 | BLOCK ASCII 20 | |___________ 21 | |___ 22 | `----> YEAH 23 | */ 24 | bar(); 25 | } 26 | } 27 | } 28 | 29 | /* block single line, no indent */ 30 | 31 | 32 | 33 | // test PR #57 34 | var obj = { /* test trailing space after multi line comment */ 35 | then: function( /* fnDone, fnFail, fnProgress */ ) { 36 | var fns = arguments; // test space before comment 37 | } 38 | }; 39 | 40 | function foo() { // single line after token that requires line break 41 | if (false) { /* multi line after token that requires line break */ 42 | bar(); 43 | } 44 | } 45 | 46 | foo 47 | .bar() 48 | 49 | // surrounded by empty lines and after chained expression 50 | 51 | // issue #139 52 | var pfun = new PFunction(function(hello /*, foo ) 53 | ,bar { */ , world) {}); 54 | -------------------------------------------------------------------------------- /lib/hooks/MemberExpression.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _tk = require('rocambole-token'); 4 | var _limit = require('../limit'); 5 | 6 | 7 | exports.format = function MemberExpression(node) { 8 | var opening = _tk.findPrevNonEmpty(node.property.startToken), 9 | closing = _tk.findNextNonEmpty(node.property.endToken); 10 | if (opening && closing && opening.value === '[' && closing.value === ']') { 11 | _limit.around(opening, 'MemberExpressionOpening'); 12 | _limit.around(closing, 'MemberExpressionClosing'); 13 | } 14 | if (opening && opening.value === '.') { 15 | _limit.around(opening, 'MemberExpressionPeriod'); 16 | } 17 | }; 18 | 19 | 20 | exports.getIndentEdges = function(node) { 21 | var edge = {}; 22 | edge.startToken = node.object.endToken; 23 | 24 | if (node.object.type !== 'CallExpression') { 25 | edge.startToken = edge.startToken.next; 26 | } 27 | 28 | edge.endToken = node.endToken; 29 | if (node.parent.type === 'CallExpression' && 30 | node.parent.callee.type === 'MemberExpression') { 31 | edge.endToken = node.parent.endToken; 32 | } 33 | 34 | // only indent if on a different line 35 | if (!_tk.findInBetween(edge.startToken, node.property.startToken, _tk.isBr)) { 36 | return false; 37 | } 38 | 39 | return edge; 40 | }; 41 | 42 | -------------------------------------------------------------------------------- /lib/hooks/ConditionalExpression.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _tk = require('rocambole-token'); 4 | var _ws = require('rocambole-whitespace'); 5 | 6 | 7 | exports.format = function ConditionalExpression(node) { 8 | // we need to grab the actual punctuators since parenthesis aren't counted 9 | // as part of test/consequent/alternate 10 | var questionMark = _tk.findNext(node.test.endToken, '?'); 11 | var colon = _tk.findNext(node.consequent.endToken, ':'); 12 | 13 | _ws.limitBefore(questionMark, _ws.expectedAfter('ConditionalExpressionTest')); 14 | _ws.limitAfter(questionMark, _ws.expectedBefore('ConditionalExpressionConsequent')); 15 | _ws.limitBefore(colon, _ws.expectedAfter('ConditionalExpressionConsequent')); 16 | _ws.limitAfter(colon, _ws.expectedBefore('ConditionalExpressionAlternate')); 17 | }; 18 | 19 | 20 | exports.getIndentEdges = function(node) { 21 | if (_tk.findInBetween(node.test.endToken, node.consequent.startToken, _tk.isBr)) { 22 | return { 23 | startToken: node.test.endToken.next, 24 | endToken: node.endToken.next 25 | }; 26 | } 27 | if (_tk.findInBetween(node.consequent.endToken, node.alternate.startToken, _tk.isBr)) { 28 | return { 29 | startToken: node.consequent.endToken.next, 30 | endToken: node.endToken.next 31 | }; 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /test/compare/default/switch_statement-out.js: -------------------------------------------------------------------------------- 1 | switch (fruit) { 2 | // case comment 3 | case Fruit.APPLE: 4 | // consequent comment 5 | apple(); 6 | break; 7 | case Fruit.BANANA: 8 | banana(); 9 | // comment in between content 10 | break; 11 | // case comment 12 | case Fruit.MANGO: 13 | // case comment 14 | case Fruit.PUPAYA: 15 | exotic(); 16 | break; 17 | default: 18 | // consequent comment 19 | unknown(); 20 | } 21 | 22 | call(function() { 23 | switch (fruit) { 24 | // case comment 25 | case Fruit.APPLE: 26 | // consequent comment 27 | exotic(); 28 | break; 29 | default: 30 | unknown(); 31 | } 32 | }); 33 | 34 | 35 | switch (fruit) { 36 | // case comment 37 | case Fruit.APPLE: 38 | // consequent comment 39 | apple(); 40 | break; 41 | } 42 | 43 | // issue #225 44 | switch (item) { 45 | case 'one': 46 | dothis() 47 | break 48 | default: 49 | } 50 | 51 | // issue #290 52 | switch (x) { 53 | case true: 54 | x(); 55 | break; 56 | default: 57 | if (x) { 58 | x(); 59 | } 60 | } 61 | 62 | // comment alignment (#209) 63 | switch (foo) { 64 | case bar: 65 | baz(); 66 | // falls through 67 | // yes, this should be aligned too 68 | 69 | // align with case 70 | case biz: 71 | what(); 72 | } 73 | -------------------------------------------------------------------------------- /test/compare/default/class_expression-in.js: -------------------------------------------------------------------------------- 1 | var foo = class Foo extends Bar { 2 | constructor (properties, name = 'lorem', ...extra) 3 | { 4 | this.properties = properties; 5 | this.name = name; 6 | this.extra = extra; 7 | } 8 | static 9 | log ( msg , level = 'log' ) { 10 | console[level](msg); 11 | } toObject () { return this.properties; } } 12 | let bar = class Foo extends Bar { 13 | // empty lines in between the MethodDefinition are valid/kept 14 | 15 | constructor(properties) { 16 | this.properties = properties; 17 | } 18 | 19 | get prop() { 20 | return 'getter'; 21 | } 22 | 23 | set prop(val) { 24 | Foo.log('setting: ', val) 25 | } 26 | 27 | static log(msg, level = 'log') { 28 | console[level]('[Foo]', msg); 29 | } 30 | 31 | toObject() { 32 | return this.properties; 33 | } 34 | 35 | } 36 | 37 | // Multi line declaration 38 | let dolor = class 39 | Foo 40 | extends 41 | Bar 42 | { 43 | } 44 | // The value to be extended can be produced by an arbitrary expression. 45 | var amet = class Foo extends BarNamespace.Bar{} 46 | let ipsum = class Foo extends BarNamespace['Bar'].Bar["Bar"]('bar').Bar("bar", "bar"){} 47 | const ullamcor = class Foo extends(BarNamespace.bar)(){} 48 | 49 | 50 | // issue #358 51 | function makeClass() { 52 | return class MyClass { 53 | method() {} 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /test/compare/default/class_expression-out.js: -------------------------------------------------------------------------------- 1 | var foo = class Foo extends Bar { 2 | constructor(properties, name = 'lorem', ...extra) { 3 | this.properties = properties; 4 | this.name = name; 5 | this.extra = extra; 6 | } 7 | static log(msg, level = 'log') { 8 | console[level](msg); 9 | } 10 | toObject() { 11 | return this.properties; 12 | } 13 | } 14 | let bar = class Foo extends Bar { 15 | // empty lines in between the MethodDefinition are valid/kept 16 | 17 | constructor(properties) { 18 | this.properties = properties; 19 | } 20 | 21 | get prop() { 22 | return 'getter'; 23 | } 24 | 25 | set prop(val) { 26 | Foo.log('setting: ', val) 27 | } 28 | 29 | static log(msg, level = 'log') { 30 | console[level]('[Foo]', msg); 31 | } 32 | 33 | toObject() { 34 | return this.properties; 35 | } 36 | 37 | } 38 | 39 | // Multi line declaration 40 | let dolor = class Foo extends Bar { 41 | } 42 | // The value to be extended can be produced by an arbitrary expression. 43 | var amet = class Foo extends BarNamespace.Bar { 44 | } 45 | let ipsum = class Foo extends BarNamespace['Bar'].Bar["Bar"]('bar').Bar("bar", "bar") { 46 | } 47 | const ullamcor = class Foo extends (BarNamespace.bar)() { 48 | } 49 | 50 | 51 | // issue #358 52 | function makeClass() { 53 | return class MyClass { 54 | method() {} 55 | }; 56 | } 57 | -------------------------------------------------------------------------------- /lib/hooks/SwitchCase.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _ws = require('rocambole-whitespace'); 4 | var _br = require('rocambole-linebreak'); 5 | var _tk = require('rocambole-token'); 6 | var limit = require('../limit'); 7 | 8 | 9 | exports.format = function SwitchCase(node) { 10 | if (node.test) { 11 | // we want case to always be on the same line! 12 | _br.limitBefore(node.test.startToken, 0); 13 | _ws.limitBefore(node.test.startToken, 1); 14 | } 15 | var endToken = node.endToken; 16 | 17 | var colon = _tk.findNext(node.startToken, ':'); 18 | limit.before(colon, 'SwitchCaseColon'); 19 | limit.after(colon, 'SwitchCaseColon'); 20 | 21 | // endToken might be ":" or "break" or ";" 22 | var breakKeyword = _tk.findInBetweenFromEnd(node.startToken, endToken.next, 'break'); 23 | if (breakKeyword) { 24 | limit.before(breakKeyword, 'BreakKeyword'); 25 | limit.after(endToken, 'BreakKeyword'); 26 | } 27 | }; 28 | 29 | 30 | exports.getIndentEdges = function(node) { 31 | return { 32 | startToken: node.startToken, 33 | // we need to get the next token because `default` might end with a `}` 34 | // (ie. IfStatement) we also need to search for next `case` or `}` or 35 | // `break` or `default` to make sure comments are included inside the range 36 | endToken: _tk.findNext(node.endToken, ['}', 'case', 'break', 'default']).prev 37 | }; 38 | }; 39 | -------------------------------------------------------------------------------- /test/compare/custom/try_statement-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "indent": { 3 | "CatchClause": 1, 4 | "TryStatement": 1 5 | }, 6 | 7 | "lineBreak": { 8 | "before": { 9 | "CatchOpeningBrace": 1, 10 | "CatchClosingBrace": ">=1", 11 | "CatchKeyword": 1, 12 | "FinallyKeyword": 1, 13 | "FinallyOpeningBrace": 1, 14 | "FinallyClosingBrace": ">=1", 15 | "TryOpeningBrace": 1, 16 | "TryClosingBrace": ">=1" 17 | }, 18 | 19 | "after": { 20 | "CatchOpeningBrace": ">=1", 21 | "CatchClosingBrace": ">=0", 22 | "CatchKeyword": 0, 23 | "FinallyOpeningBrace": ">=1", 24 | "FinallyClosingBrace": ">=1", 25 | "TryOpeningBrace": ">=1", 26 | "TryClosingBrace": 1 27 | } 28 | }, 29 | 30 | "whiteSpace": { 31 | "before": { 32 | "CatchParameterList": 0, 33 | "CatchOpeningBrace": 1, 34 | "CatchClosingBrace": 1, 35 | "CatchKeyword": 1, 36 | "FinallyOpeningBrace": 1, 37 | "FinallyClosingBrace": 1, 38 | "TryOpeningBrace": 1, 39 | "TryClosingBrace": 1 40 | }, 41 | 42 | "after": { 43 | "CatchParameterList": 0, 44 | "CatchOpeningBrace": 1, 45 | "CatchClosingBrace": 1, 46 | "CatchKeyword": 1, 47 | "FinallyOpeningBrace": 1, 48 | "FinallyClosingBrace": 1, 49 | "TryOpeningBrace": 1, 50 | "TryClosingBrace": 1 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/hooks/TryStatement.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _tk = require('rocambole-token'); 4 | var _limit = require('../limit'); 5 | 6 | 7 | exports.format = function TryStatement(node) { 8 | var finalizer = node.finalizer; 9 | if (finalizer) { 10 | var finallyKeyword = _tk.findPrev(finalizer.startToken, 'finally'); 11 | _limit.around(finallyKeyword, 'FinallyKeyword'); 12 | _limit.around(finalizer.startToken, 'FinallyOpeningBrace'); 13 | _limit.around(finalizer.endToken, 'FinallyClosingBrace'); 14 | 15 | if (!finalizer.body.length && !containsCommentsInside(finalizer)) { 16 | // XXX: empty body, so we should remove all white spaces 17 | _tk.removeEmptyInBetween(finalizer.startToken, finalizer.endToken); 18 | } 19 | } 20 | 21 | // CatchClause is handled by its own hook 22 | 23 | _limit.around(node.startToken, 'TryKeyword'); 24 | _limit.around(node.block.startToken, 'TryOpeningBrace'); 25 | _limit.around(node.block.endToken, 'TryClosingBrace'); 26 | }; 27 | 28 | 29 | function containsCommentsInside(node) { 30 | return !!_tk.findInBetween(node.startToken, node.endToken, _tk.isComment); 31 | } 32 | 33 | 34 | exports.getIndentEdges = function(node) { 35 | var edges = [node.block]; 36 | 37 | if (node.finalizer) { 38 | edges.push(node.finalizer); 39 | } 40 | 41 | // CatchClause is handled by it's own node (automatically) 42 | 43 | return edges; 44 | }; 45 | -------------------------------------------------------------------------------- /lib/hooks/ImportSpecifier.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // this logic is shared with ExportSpecifier 4 | 5 | var _br = require('rocambole-linebreak'); 6 | var _tk = require('rocambole-token'); 7 | var _ws = require('rocambole-whitespace'); 8 | 9 | exports.format = function(node) { 10 | var braceStart = _tk.findPrev(node.startToken, _tk.isCode); 11 | var braceEnd = _tk.findNext(node.endToken, _tk.isCode); 12 | 13 | // handle `import foo, { lorem, ipsum } from 'lib';` 14 | if (braceStart.value === '{' || braceStart.value === ',') { 15 | _br.limit(braceStart, 0); 16 | _ws.limitBefore(braceStart, braceStart.value === '{' ? 1 : 0); 17 | _ws.limitAfter(braceStart, braceStart.value === '{' ? 'ModuleSpecifierOpeningBrace' : 1); 18 | } 19 | 20 | if (braceEnd.value === '}' || braceEnd.value === ',') { 21 | _br.limit(braceEnd, 0); 22 | var next = _tk.findNextNonEmpty(braceEnd); 23 | _ws.limitAfter(braceEnd, next.value === ';' ? 0 : 1); 24 | _ws.limitBefore(braceEnd, braceEnd.value === '}' ? 'ModuleSpecifierClosingBrace' : 0); 25 | } 26 | 27 | _br.limit(node.startToken, 0); 28 | _br.limit(node.endToken, 0); 29 | 30 | if (node.startToken !== node.endToken) { 31 | // handle spaces around "as" 32 | // eg: `import { named1 as myNamed1 } from 'lib'` 33 | // eg: `import * as myLib from 'lib'` 34 | _ws.limitAfter(node.startToken, 1); 35 | _ws.limitBefore(node.endToken, 1); 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /lib/hooks/WhileStatement.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _tk = require('rocambole-token'); 4 | var _limit = require('../limit'); 5 | 6 | 7 | exports.format = function WhileStatement(node) { 8 | var conditionalStart = _tk.findNext(node.startToken, '('); 9 | var conditionalEnd = _tk.findPrev(node.body.startToken, ')'); 10 | 11 | _limit.around(conditionalStart, 'WhileStatementConditionalOpening'); 12 | 13 | if (node.body.type === 'BlockStatement') { 14 | var bodyStart = node.body.startToken; 15 | var bodyEnd = node.body.endToken; 16 | _limit.around(bodyStart, 'WhileStatementOpeningBrace'); 17 | _limit.around(bodyEnd, 'WhileStatementClosingBrace'); 18 | _limit.around(conditionalEnd, 'WhileStatementConditionalClosing'); 19 | } else { 20 | var next = _tk.findNextNonEmpty(conditionalEnd); 21 | _limit.before(conditionalEnd, 'WhileStatementConditionalClosing'); 22 | if (_tk.isSemiColon(next)) { 23 | _limit.after(conditionalEnd, 0); 24 | } else { 25 | _limit.after(conditionalEnd, 'WhileStatementConditionalClosing'); 26 | } 27 | } 28 | }; 29 | 30 | 31 | exports.getIndentEdges = function(node) { 32 | var edges = [ 33 | { 34 | startToken: _tk.findNext(node.startToken, '('), 35 | endToken: _tk.findPrev(node.body.startToken, ')') 36 | } 37 | ]; 38 | 39 | if (node.body.type !== 'EmptyStatement') { 40 | edges.push(node.body); 41 | } 42 | 43 | return edges; 44 | }; 45 | -------------------------------------------------------------------------------- /test/compare/default/assignment_expression-in.js: -------------------------------------------------------------------------------- 1 | foo=bar; lorem =123 2 | dolor = "amet" 3 | 4 | // yes, this is valid JS 5 | maecennas 6 | 7 | += 8 | 9 | "ullamcor" 10 | // end multi-line 11 | 12 | 13 | foo = fn(1); 14 | 15 | 16 | // assignment operators 17 | 18 | x+= y 19 | x -= y 20 | x *= y 21 | x /= y 22 | x%= y 23 | x<<= y 24 | x >>= y 25 | x 26 | >>>= 27 | y 28 | x&= y 29 | x^=y 30 | x|=y 31 | 32 | 33 | // multiple same line 34 | this.a=b;this.c=d;this.e=f;this.g=h||0; 35 | 36 | function h(a,b,c,d,e){this._listener=b;this._isOnce=c;this.context=d;this._signal=a;this._priority=e||0} 37 | 38 | 39 | // test for issue #5 (related to parenthesis) 40 | doc=(context&&context.nodeType?context.ownerDocument||context:document); 41 | 42 | 43 | // issue #8 (multiple assignment + OR + indent) 44 | function iss8(){ 45 | if (proxy) { 46 | proxy.guid = fn.guid = fn.guid || jQuery.guid++; 47 | } 48 | } 49 | 50 | // issue #306: UnaryExpression 51 | hasNativeRequestAnimationFrame = !!( 52 | window.requestAnimationFrame || 53 | window.webkitRequestAnimationFrame || 54 | window.mozRequestAnimationFrame || 55 | window.msRequestAnimationFrame 56 | ); 57 | 58 | // issue #316 59 | export class Foobar extends EventEmitter { 60 | constructor(foo, bar, d = {}) { 61 | super(); 62 | var fooBar = { foo, bar }; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /test/compare/default/module-out.js: -------------------------------------------------------------------------------- 1 | // samples borrowed from http://www.2ality.com/2014/09/es6-modules-final.html 2 | 3 | // Default exports and named exports 4 | import theDefault, { named1, named2 } from 'src/mylib'; 5 | import theDefault from 'src/mylib'; 6 | import { named1, named2 } from 'src/mylib'; 7 | 8 | // Renaming: import named1 as myNamed1 9 | import { named1 as myNamed1, named2 } from 'src/mylib'; 10 | 11 | // Importing the module as an object 12 | // (with one property per named export) 13 | import * as mylib from 'src/mylib'; 14 | 15 | // Only load the module, don’t import anything 16 | import 'src/mylib'; 17 | 18 | export var myVar1 = 123; 19 | export let myVar2 = 'foo'; 20 | export const MY_CONST = 'BAR'; 21 | 22 | export function myFunc() { 23 | return 'myfunc'; 24 | } 25 | 26 | export function* myGeneratorFunc() { 27 | return yield someStuff(); 28 | } 29 | export class MyClass { 30 | constructor() { 31 | this.name = 'exports test'; 32 | } 33 | } 34 | 35 | export default 123; 36 | export default function (x) { 37 | return x 38 | } 39 | export default x => x; 40 | export default class { 41 | constructor(x, y) { 42 | this.x = x; 43 | this.y = y; 44 | } 45 | } 46 | 47 | export { MY_CONST, myFunc }; 48 | export { MY_CONST as THE_CONST, myFunc as theFunc }; 49 | 50 | export * from 'src/other_module'; 51 | export { foo, bar } from 'src/other_module'; 52 | export { foo as myFoo, bar } from 'src/other_module'; 53 | -------------------------------------------------------------------------------- /test/compare/default/assignment_expression-out.js: -------------------------------------------------------------------------------- 1 | foo = bar; 2 | lorem = 123 3 | dolor = "amet" 4 | 5 | // yes, this is valid JS 6 | maecennas += "ullamcor" 7 | // end multi-line 8 | 9 | 10 | foo = fn(1); 11 | 12 | 13 | // assignment operators 14 | 15 | x += y 16 | x -= y 17 | x *= y 18 | x /= y 19 | x %= y 20 | x <<= y 21 | x >>= y 22 | x >>>= y 23 | x &= y 24 | x ^= y 25 | x |= y 26 | 27 | 28 | // multiple same line 29 | this.a = b; 30 | this.c = d; 31 | this.e = f; 32 | this.g = h || 0; 33 | 34 | function h(a, b, c, d, e) { 35 | this._listener = b; 36 | this._isOnce = c; 37 | this.context = d; 38 | this._signal = a; 39 | this._priority = e || 0 40 | } 41 | 42 | 43 | // test for issue #5 (related to parenthesis) 44 | doc = (context && context.nodeType ? context.ownerDocument || context : document); 45 | 46 | 47 | // issue #8 (multiple assignment + OR + indent) 48 | function iss8() { 49 | if (proxy) { 50 | proxy.guid = fn.guid = fn.guid || jQuery.guid++; 51 | } 52 | } 53 | 54 | // issue #306: UnaryExpression 55 | hasNativeRequestAnimationFrame = !!( 56 | window.requestAnimationFrame || 57 | window.webkitRequestAnimationFrame || 58 | window.mozRequestAnimationFrame || 59 | window.msRequestAnimationFrame 60 | ); 61 | 62 | // issue #316 63 | export class Foobar extends EventEmitter { 64 | constructor(foo, bar, d = {}) { 65 | super(); 66 | var fooBar = { 67 | foo, 68 | bar 69 | }; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /test/compare/default/switch_statement-in.js: -------------------------------------------------------------------------------- 1 | switch (fruit) { 2 | // case comment 3 | case Fruit.APPLE: 4 | // consequent comment 5 | apple(); 6 | break; 7 | case 8 | Fruit.BANANA: 9 | banana(); 10 | // comment in between content 11 | break; 12 | // case comment 13 | case Fruit.MANGO: 14 | // case comment 15 | case Fruit.PUPAYA: 16 | exotic(); 17 | break; 18 | default: 19 | // consequent comment 20 | unknown(); 21 | } 22 | 23 | call(function(){ 24 | switch (fruit) { 25 | // case comment 26 | case Fruit.APPLE: 27 | // consequent comment 28 | exotic(); 29 | break; 30 | default: 31 | unknown(); 32 | } 33 | }); 34 | 35 | 36 | switch (fruit) 37 | { 38 | // case comment 39 | case Fruit.APPLE: 40 | // consequent comment 41 | apple(); 42 | break; } 43 | 44 | // issue #225 45 | switch (item) { 46 | case 'one': 47 | dothis() 48 | break 49 | default: 50 | } 51 | 52 | // issue #290 53 | switch (x) { 54 | case true: 55 | x(); 56 | break; 57 | default: 58 | if (x) { 59 | x(); 60 | } 61 | } 62 | 63 | // comment alignment (#209) 64 | switch (foo) { 65 | case bar: 66 | baz(); 67 | // falls through 68 | // yes, this should be aligned too 69 | 70 | // align with case 71 | case biz: 72 | what(); 73 | } 74 | -------------------------------------------------------------------------------- /test/pipe.spec.js: -------------------------------------------------------------------------------- 1 | //jshint node:true 2 | /*global describe, it*/ 3 | "use strict"; 4 | 5 | var expect = require('chai').expect; 6 | var esformatter = require('../lib/esformatter'); 7 | 8 | var input = 'var foo = bar;\nfunction bar(dolor, amet) {\n return dolor + amet;\n}'; 9 | var output1 = '\n// ---- esformatter-pipe-test-1 ---\n'; 10 | var output2 = '\n// ---- esformatter-pipe-test-2 ---\n'; 11 | 12 | describe('pipe', function() { 13 | 14 | it('should call piped commands', function() { 15 | var out = esformatter.format(input, { 16 | pipe: { 17 | before: [ 18 | 'esformatter-pipe-test-1', 19 | ], 20 | after: [ 21 | 'esformatter-pipe-test-2' 22 | ] 23 | } 24 | }); 25 | expect(out).to.eql(input + output1 + output2); 26 | }); 27 | 28 | it('should call piped commands in order', function() { 29 | var out = esformatter.format(input, { 30 | pipe: { 31 | after: [ 32 | 'esformatter-pipe-test-2', 33 | 'esformatter-pipe-test-1' 34 | ] 35 | } 36 | }); 37 | expect(out).to.eql(input + output2 + output1); 38 | }); 39 | 40 | it('should throw error if command not found', function() { 41 | expect(function() { 42 | esformatter.format(input, { 43 | pipe: { 44 | before: [ 45 | 'esformatter-fake-pipe-command' 46 | ] 47 | } 48 | }); 49 | }).to.throw(); 50 | }); 51 | 52 | }); 53 | -------------------------------------------------------------------------------- /test/compare/custom/module-out.js: -------------------------------------------------------------------------------- 1 | // samples borrowed from http://www.2ality.com/2014/09/es6-modules-final.html 2 | 3 | // Default exports and named exports 4 | import theDefault, { named1, named2 } from 'src/mylib'; 5 | import theDefault from 'src/mylib'; 6 | import { named1, named2 } from 'src/mylib'; 7 | 8 | // Renaming: import named1 as myNamed1 9 | import { named1 as myNamed1, named2 } from 'src/mylib'; 10 | 11 | // Importing the module as an object 12 | // (with one property per named export) 13 | import * as mylib from 'src/mylib'; 14 | 15 | // Only load the module, don’t import anything 16 | import 'src/mylib'; 17 | 18 | export var myVar1 = 123; 19 | export let myVar2 = 'foo'; 20 | export const MY_CONST = 'BAR'; 21 | 22 | export function myFunc() { 23 | return 'myfunc'; 24 | } 25 | 26 | export function* myGeneratorFunc() { 27 | return yield someStuff(); 28 | } 29 | export class MyClass { 30 | constructor() { 31 | this.name = 'exports test'; 32 | } 33 | } 34 | 35 | export default 123; 36 | export default function (x) { 37 | return x 38 | } 39 | export default x => x; 40 | export default class { 41 | constructor(x, y) { 42 | this.x = x; 43 | this.y = y; 44 | } 45 | } 46 | 47 | export { MY_CONST, myFunc }; 48 | export { MY_CONST as THE_CONST, myFunc as theFunc }; 49 | 50 | export * from 'src/other_module'; 51 | export { foo, bar } from 'src/other_module'; 52 | export { foo as myFoo, bar } from 'src/other_module'; 53 | -------------------------------------------------------------------------------- /test/compare/default/comments-in.js: -------------------------------------------------------------------------------- 1 | // line comment, no indent 2 | 3 | /* 4 | * block comment, no indent 5 | */ 6 | if (true) { 7 | // line comment, 1 indent 8 | /** 9 | * block comment, 1 indent 10 | */ 11 | if (true) { 12 | // line comment, 2 indents 13 | /* 14 | * block comment, 2 indent 15 | */ 16 | if (true) { 17 | /* block single line, 3 indents */ 18 | /* 19 | BLOCK ASCII 20 | |___________ 21 | |___ 22 | `----> YEAH 23 | */ 24 | bar(); 25 | } 26 | } 27 | } 28 | 29 | /* block single line, no indent */ 30 | 31 | 32 | 33 | // test PR #57 34 | var obj = { /* test trailing space after multi line comment */ 35 | then: function( /* fnDone, fnFail, fnProgress */ ) { 36 | var fns = arguments; // test space before comment 37 | } 38 | }; 39 | 40 | function foo() { // single line after token that requires line break 41 | if (false) { /* multi line after token that requires line break */ 42 | bar(); 43 | } 44 | } 45 | 46 | foo 47 | .bar() 48 | 49 | // surrounded by empty lines and after chained expression 50 | 51 | // issue #139 52 | var pfun = new PFunction(function (hello /*, foo ) 53 | ,bar { */,world) {}); 54 | -------------------------------------------------------------------------------- /lib/hooks/ForStatement.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _tk = require('rocambole-token'); 4 | var _ws = require('rocambole-whitespace'); 5 | var _limit = require('../limit'); 6 | 7 | 8 | exports.format = function ForStatement(node) { 9 | var semi_1 = _tk.findNext(node.startToken, ';'); 10 | var semi_2 = _tk.findPrev(node.body.startToken, ';'); 11 | _ws.limit(semi_1, 'ForStatementSemicolon'); 12 | _ws.limit(semi_2, 'ForStatementSemicolon'); 13 | 14 | var expressionStart = _tk.findNext(node.startToken, '('); 15 | var expressionEnd = _tk.findPrev(node.body.startToken, ')'); 16 | _limit.around(expressionStart, 'ForStatementExpressionOpening'); 17 | _limit.around(expressionEnd, 'ForStatementExpressionClosing'); 18 | 19 | if (node.body.type === 'BlockStatement') { 20 | var bodyStart = node.body.startToken; 21 | var bodyEnd = node.body.endToken; 22 | _limit.around(bodyStart, 'ForStatementOpeningBrace'); 23 | _limit.around(bodyEnd, 'ForStatementClosingBrace'); 24 | } 25 | }; 26 | 27 | 28 | exports.getIndentEdges = function(node) { 29 | var edges = []; 30 | 31 | var args = { 32 | startToken: _tk.findNext(node.startToken, '('), 33 | endToken: _tk.findPrev(node.body.startToken, ')') 34 | }; 35 | edges.push(args); 36 | 37 | if (node.body.type === 'BlockStatement') { 38 | edges.push(node.body); 39 | } else { 40 | edges.push({ 41 | startToken: args.endToken, 42 | endToken: node.endToken 43 | }); 44 | } 45 | 46 | return edges; 47 | }; 48 | -------------------------------------------------------------------------------- /lib/hooks/ArrowFunctionExpression.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var tk = require('rocambole-token'); 4 | var limit = require('../limit'); 5 | var _params = require('./Params'); 6 | 7 | exports.format = function ArrowFunctionExpression(node) { 8 | var body = node.body; 9 | if (body.type === 'BlockStatement') { 10 | limit.around(body.startToken, 'ArrowFunctionExpressionOpeningBrace'); 11 | limit.around(body.endToken, 'ArrowFunctionExpressionClosingBrace'); 12 | } 13 | 14 | var arrow = tk.findPrev(body.startToken, '=>'); 15 | limit.around(arrow, 'ArrowFunctionExpressionArrow'); 16 | 17 | // make sure we handle `(x) => x` and `x => x` 18 | if (shouldHandleParams(node)) { 19 | _params.format(node); 20 | } 21 | }; 22 | 23 | exports.getIndentEdges = function(node, opts) { 24 | var edges = []; 25 | if (shouldIndentBody(node, opts)) { 26 | edges.push(node.body); 27 | } 28 | if (shouldHandleParams(node)) { 29 | edges.push(_params.getIndentEdges(node, opts)); 30 | } 31 | return edges; 32 | }; 33 | 34 | function shouldHandleParams(node) { 35 | var arrow = tk.findPrev(node.body.startToken, '=>'); 36 | // we don't check based on `node.params` because of `node.defaults` 37 | return tk.findPrevNonEmpty(arrow).value === ')'; 38 | } 39 | 40 | function shouldIndentBody(node, opts) { 41 | // we don't want to indent the body twice if ObjectExpression or 42 | // ArrayExpression or CallExpression 43 | return node.body.type === 'BlockStatement' || !opts[node.body.type]; 44 | } 45 | -------------------------------------------------------------------------------- /test/compare/custom/module-in.js: -------------------------------------------------------------------------------- 1 | // samples borrowed from http://www.2ality.com/2014/09/es6-modules-final.html 2 | 3 | // Default exports and named exports 4 | import theDefault, 5 | {named1, 6 | named2} from 'src/mylib'; 7 | import 8 | theDefault from 'src/mylib'; 9 | import 10 | { named1, named2 } 11 | from 12 | 'src/mylib'; 13 | 14 | // Renaming: import named1 as myNamed1 15 | import { named1 as myNamed1, named2 } from 'src/mylib'; 16 | 17 | // Importing the module as an object 18 | // (with one property per named export) 19 | import * as mylib from 'src/mylib'; 20 | 21 | // Only load the module, don’t import anything 22 | import 'src/mylib'; 23 | 24 | export var myVar1 = 123; 25 | export let myVar2 = 'foo'; 26 | export const MY_CONST = 'BAR'; 27 | 28 | export 29 | function myFunc() { 30 | return 'myfunc'; 31 | } 32 | 33 | export function* myGeneratorFunc() { 34 | return yield someStuff(); 35 | } 36 | export class MyClass { 37 | constructor() { 38 | this.name = 'exports test'; 39 | } 40 | } 41 | 42 | export 43 | default 123; 44 | export default function (x) { 45 | return x 46 | } 47 | export default x => x; 48 | export default class { 49 | constructor(x, y) { 50 | this.x = x; 51 | this.y = y; 52 | } 53 | } 54 | 55 | export { MY_CONST, myFunc }; 56 | export { MY_CONST as THE_CONST, myFunc as theFunc }; 57 | 58 | export * from 'src/other_module'; 59 | export { foo , bar }from 'src/other_module'; 60 | export {foo as myFoo,bar} from 'src/other_module'; 61 | -------------------------------------------------------------------------------- /test/compare/default/module-in.js: -------------------------------------------------------------------------------- 1 | // samples borrowed from http://www.2ality.com/2014/09/es6-modules-final.html 2 | 3 | // Default exports and named exports 4 | import theDefault, 5 | {named1, 6 | named2} from 'src/mylib'; 7 | import 8 | theDefault from 'src/mylib'; 9 | import 10 | { named1, named2 } 11 | from 12 | 'src/mylib'; 13 | 14 | // Renaming: import named1 as myNamed1 15 | import { named1 as myNamed1, named2 } from 'src/mylib'; 16 | 17 | // Importing the module as an object 18 | // (with one property per named export) 19 | import * as mylib from 'src/mylib'; 20 | 21 | // Only load the module, don’t import anything 22 | import 'src/mylib'; 23 | 24 | export var myVar1 = 123; 25 | export let myVar2 = 'foo'; 26 | export const MY_CONST = 'BAR'; 27 | 28 | export 29 | function myFunc() { 30 | return 'myfunc'; 31 | } 32 | 33 | export function* myGeneratorFunc() { 34 | return yield someStuff(); 35 | } 36 | export class MyClass { 37 | constructor() { 38 | this.name = 'exports test'; 39 | } 40 | } 41 | 42 | export 43 | default 123; 44 | export default function (x) { 45 | return x 46 | } 47 | export default x => x; 48 | export default class { 49 | constructor(x, y) { 50 | this.x = x; 51 | this.y = y; 52 | } 53 | } 54 | 55 | export { MY_CONST, myFunc }; 56 | export { MY_CONST as THE_CONST, myFunc as theFunc }; 57 | 58 | export * from 'src/other_module'; 59 | export { foo , bar }from 'src/other_module'; 60 | export {foo as myFoo,bar} from 'src/other_module'; 61 | -------------------------------------------------------------------------------- /test/compare/default/var-out.js: -------------------------------------------------------------------------------- 1 | var foo = true; 2 | var bar = '123'; 3 | var lorem = /\w+/; 4 | var parentheses = (123); 5 | 6 | var dolor; 7 | 8 | var a, 9 | b = true, 10 | c = 3, 11 | d = false; 12 | 13 | var amet = qwe(); 14 | var asi = true 15 | 16 | 17 | // test for issue #4 18 | var 19 | // foo var 20 | foo, 21 | // bar variable 22 | bar = 'dolor amet'; 23 | 24 | 25 | // issue #28 : comma first 26 | var x = 33, 27 | y = 12, 28 | 29 | 30 | // comment 31 | w = 45; 32 | 33 | 34 | // issue #31: multiple var declaration + function expression = wrong indent 35 | (function() { 36 | var 37 | // A central reference to the root jQuery(document) 38 | rootjQuery, 39 | 40 | // Define a local copy of jQuery 41 | jQuery = function(selector, context) { 42 | // The jQuery object is actually just the init constructor 'enhanced' 43 | return new jQuery.fn.init(selector, context, rootjQuery); 44 | }, 45 | 46 | // literal object 47 | obj = { 48 | num: 123, 49 | str: 'literal' 50 | }; 51 | }()); 52 | 53 | var lorem = ipsum || 54 | dolor && 55 | (sit || amet); 56 | 57 | // issue #306: UnaryExpression 58 | var hasNativeRequestAnimationFrame = !!( 59 | window.requestAnimationFrame || 60 | window.webkitRequestAnimationFrame || 61 | window.mozRequestAnimationFrame || 62 | window.msRequestAnimationFrame 63 | ); 64 | 65 | // issue #334 66 | var a = 'foo'; 67 | var b = '3'; 68 | 69 | // comma-first + asi 70 | var foo = 123, 71 | bar = 456; 72 | [1, 2, 3].forEach(echo) 73 | -------------------------------------------------------------------------------- /test/compare/default/var-in.js: -------------------------------------------------------------------------------- 1 | var foo=true;var bar= '123'; 2 | var lorem = 3 | /\w+/; 4 | var parentheses =(123); 5 | 6 | var dolor; 7 | 8 | var a,b= true, 9 | c =3, d=false; 10 | 11 | var 12 | 13 | amet= qwe(); 14 | var asi = true 15 | 16 | 17 | // test for issue #4 18 | var 19 | // foo var 20 | foo, 21 | // bar variable 22 | bar = 'dolor amet'; 23 | 24 | 25 | // issue #28 : comma first 26 | var x=33 27 | ,y=12 28 | 29 | 30 | // comment 31 | , w = 45; 32 | 33 | 34 | // issue #31: multiple var declaration + function expression = wrong indent 35 | (function(){ 36 | var 37 | // A central reference to the root jQuery(document) 38 | rootjQuery, 39 | 40 | // Define a local copy of jQuery 41 | jQuery = function( selector, context ) { 42 | // The jQuery object is actually just the init constructor 'enhanced' 43 | return new jQuery.fn.init( selector, context, rootjQuery ); 44 | }, 45 | 46 | // literal object 47 | obj = { 48 | num : 123, 49 | str : 'literal' 50 | }; 51 | }()); 52 | 53 | var lorem = ipsum || 54 | dolor && 55 | (sit || amet); 56 | 57 | // issue #306: UnaryExpression 58 | var hasNativeRequestAnimationFrame = !!( 59 | window.requestAnimationFrame || 60 | window.webkitRequestAnimationFrame || 61 | window.mozRequestAnimationFrame || 62 | window.msRequestAnimationFrame 63 | ); 64 | 65 | // issue #334 66 | var a = 'foo' ; 67 | var b = '3' 68 | ; 69 | 70 | // comma-first + asi 71 | var foo = 123 72 | , bar = 456 73 | ;[1,2,3].forEach(echo) 74 | -------------------------------------------------------------------------------- /bin/esformatter: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | "use strict"; 3 | 4 | // resolve allow us to load the locally installed esformatter instead of using 5 | // the global version 6 | var requireResolve = require('resolve').sync; 7 | var path = require('path'); 8 | var dirname = path.dirname; 9 | var pathResolve = path.resolve; 10 | 11 | var argv = process.argv.slice(2); 12 | 13 | // if user sets a config file we use that as the base directory to start the 14 | // search because we assume that some settings aren't backwards compatible 15 | // otherwise we just use the process.cwd() 16 | var opts = require('../lib/cli.js').parse(argv); 17 | var basedir = opts.config ? 18 | pathResolve(dirname(opts.config)) : 19 | process.cwd(); 20 | 21 | var cliPath; 22 | try { 23 | cliPath = requireResolve('esformatter', { 24 | basedir: basedir 25 | }); 26 | cliPath = pathResolve(dirname(cliPath), './cli.js'); 27 | } catch (err) { 28 | // fallback to this version instead 29 | cliPath = '../lib/cli.js'; 30 | } 31 | 32 | var cli = require(cliPath); 33 | // until v0.5 the cli module only exposed a single `parse` method, after v0.6 34 | // we expose 2 methods to allow processing the data before executing the 35 | // command (all the logic above) 36 | if ('run' in cli) { 37 | process.on('exit', function(code) { 38 | if (code === 0 && cli.exitCode) { 39 | // if node detected a different error we let it use the standard error 40 | // code: https://nodejs.org/api/process.html#process_exit_codes 41 | // otherwise we make sure it's set to 1 if we had any errors 42 | process.exit(cli.exitCode); 43 | } 44 | }); 45 | cli.run(cli.parse(argv)); 46 | } else { 47 | cli.parse(argv); 48 | } 49 | -------------------------------------------------------------------------------- /lib/hooks/ForInStatement.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _br = require('rocambole-linebreak'); 4 | var _tk = require('rocambole-token'); 5 | var _ws = require('rocambole-whitespace'); 6 | 7 | 8 | exports.format = function ForInStatement(node) { 9 | var expressionStart = _tk.findNext(node.startToken, '('); 10 | var expressionEnd = _tk.findPrev(node.body.startToken, ')'); 11 | 12 | _br.limit(expressionStart, 'ForInStatementExpressionOpening'); 13 | _ws.limit(expressionStart, 'ForInStatementExpressionOpening'); 14 | 15 | _br.limit(expressionEnd, 'ForInStatementExpressionClosing'); 16 | _ws.limit(expressionEnd, 'ForInStatementExpressionClosing'); 17 | 18 | if (node.body.type === 'BlockStatement' && node.body.body.length) { 19 | var bodyStart = node.body.startToken; 20 | var bodyEnd = node.body.endToken; 21 | 22 | _br.limit(bodyStart, 'ForInStatementOpeningBrace'); 23 | _ws.limit(bodyStart, 'ForInStatementOpeningBrace'); 24 | 25 | _br.limit(bodyEnd, 'ForInStatementClosingBrace'); 26 | _ws.limit(bodyEnd, 'ForInStatementClosingBrace'); 27 | 28 | _ws.limitAfter(expressionEnd, 'ForInStatementExpression'); 29 | } 30 | 31 | _ws.limitAfter(node.left.endToken, 1); 32 | _ws.limitBefore(node.right.startToken, 1); 33 | }; 34 | 35 | 36 | exports.getIndentEdges = function(node) { 37 | var edges = []; 38 | 39 | edges.push({ 40 | startToken: node.left.startToken, 41 | endToken: node.right.endToken 42 | }); 43 | 44 | if (node.body.type === 'BlockStatement') { 45 | edges.push(node.body); 46 | } else { 47 | edges.push({ 48 | startToken: _tk.findNext(node.right.endToken, ')').next, 49 | endToken: node.endToken 50 | }); 51 | } 52 | 53 | return edges; 54 | }; 55 | -------------------------------------------------------------------------------- /lib/hooks/ForOfStatement.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _br = require('rocambole-linebreak'); 4 | var _tk = require('rocambole-token'); 5 | var _ws = require('rocambole-whitespace'); 6 | 7 | 8 | exports.format = function ForOfStatement(node) { 9 | var expressionStart = _tk.findNext(node.startToken, '('); 10 | var expressionEnd = _tk.findPrev(node.body.startToken, ')'); 11 | 12 | _br.limit(expressionStart, 'ForOfStatementExpressionOpening'); 13 | _ws.limit(expressionStart, 'ForOfStatementExpressionOpening'); 14 | 15 | _br.limit(expressionEnd, 'ForOfStatementExpressionClosing'); 16 | _ws.limit(expressionEnd, 'ForOfStatementExpressionClosing'); 17 | 18 | if (node.body.type === 'BlockStatement' && node.body.body.length) { 19 | var bodyStart = node.body.startToken; 20 | var bodyEnd = node.body.endToken; 21 | 22 | _br.limit(bodyStart, 'ForOfStatementOpeningBrace'); 23 | _ws.limit(bodyStart, 'ForOfStatementOpeningBrace'); 24 | 25 | _br.limit(bodyEnd, 'ForOfStatementClosingBrace'); 26 | _ws.limit(bodyEnd, 'ForOfStatementClosingBrace'); 27 | 28 | _ws.limitAfter(expressionEnd, 'ForOfStatementExpression'); 29 | } 30 | 31 | _ws.limitAfter(node.left.endToken, 1); 32 | _ws.limitBefore(node.right.startToken, 1); 33 | }; 34 | 35 | 36 | exports.getIndentEdges = function(node) { 37 | var edges = []; 38 | 39 | edges.push({ 40 | startToken: node.left.startToken, 41 | endToken: node.right.endToken 42 | }); 43 | 44 | if (node.body.type === 'BlockStatement') { 45 | edges.push(node.body); 46 | } else { 47 | edges.push({ 48 | startToken: _tk.findNext(node.right.endToken, ')').next, 49 | endToken: node.endToken 50 | }); 51 | } 52 | 53 | return edges; 54 | }; 55 | -------------------------------------------------------------------------------- /test/helpers.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // 4 | // helpers used on the specs 5 | // 6 | 7 | 8 | var _fs = require('fs'); 9 | var _path = require('path'); 10 | var stripJsonComments = require('strip-json-comments'); 11 | 12 | 13 | // --- 14 | 15 | 16 | exports.CACHE = {}; 17 | exports.COMPARE_FOLDER = _path.join(__dirname, 'compare'); 18 | 19 | 20 | // --- 21 | 22 | 23 | exports.readIn = function(id) { 24 | return exports.readFile(_path.join(exports.COMPARE_FOLDER, id + '-in.js')); 25 | }; 26 | 27 | 28 | exports.readOut = function(id) { 29 | return exports.readFile(_path.join(exports.COMPARE_FOLDER, id + '-out.js')); 30 | }; 31 | 32 | 33 | exports.readConfig = function(id) { 34 | var filePath = _path.join(exports.COMPARE_FOLDER, id + '-config.json'); 35 | return JSON.parse(stripJsonComments(exports.readFile(filePath) + '\n')); 36 | }; 37 | 38 | 39 | exports.readFile = function(path) { 40 | // we cache the results to avoid redundant I/O 41 | if (!(path in exports.CACHE)) { 42 | exports.CACHE[path] = exports.lineFeed(_fs.readFileSync(path).toString()); 43 | } 44 | return exports.CACHE[path]; 45 | }; 46 | 47 | 48 | exports.purge = function(dir) { 49 | if (!exports.SHOULD_PURGE) return; 50 | _fs.readdirSync(dir).forEach(function(relPath) { 51 | var path = _path.join(dir, relPath); 52 | if (_fs.statSync(path).isDirectory()) { 53 | exports.purge(path); 54 | } else { 55 | _fs.unlinkSync(path); 56 | } 57 | }); 58 | _fs.rmdirSync(dir); 59 | }; 60 | 61 | 62 | exports.mkdir = function(dir) { 63 | if (!_fs.existsSync(dir)) { 64 | _fs.mkdirSync(dir); 65 | } 66 | }; 67 | 68 | exports.lineFeed = function(text) { 69 | return text.replace(/\r\n?|[\n\u2028\u2029]/g, "\n"); 70 | }; 71 | -------------------------------------------------------------------------------- /test/compare/default/function_expression-out.js: -------------------------------------------------------------------------------- 1 | var a = function() { 2 | return 'b'; 3 | }; 4 | 5 | b = function doB(q, wer, ty) { 6 | var c = function(n) { 7 | return function() { 8 | return q + 9 | wer - ty; 10 | } 11 | } 12 | return c 13 | } 14 | 15 | this.foo = { 16 | bar: function() { 17 | var r = function() { 18 | re(); draw(); 19 | return log('foo') + 'bar'; 20 | }; 21 | }, 22 | ipsum: function(amet) { 23 | return function() { 24 | amet() 25 | } 26 | } 27 | }; 28 | 29 | var noop = function() {}; 30 | 31 | 32 | var add = function(a, b) { 33 | return a + b; 34 | } 35 | 36 | call(function(a) { 37 | b(); 38 | }); 39 | 40 | 41 | // issue #36 42 | var obj = { 43 | then: function( /* fnDone, fnFail, fnProgress */ ) { 44 | var fns = arguments; 45 | } 46 | }; 47 | 48 | 49 | // issue #134 50 | var foo = new MyConstructor(function otherFunction() {}); 51 | 52 | 53 | 54 | // issue #143 55 | if (!this._pollReceive) { 56 | this._pollReceive = nn.PollReceiveSocket(this.binding, function(events) { 57 | if (events) this._receive(); 58 | }.bind(this)); 59 | } 60 | 61 | // issue #283 62 | var foo = function foo() { 63 | bar() 64 | } 65 | 66 | var foo = function() { 67 | bar() 68 | } 69 | 70 | // default params (#285) 71 | var defaultParams = function defaults(z, x = 1, y = 2) { 72 | return z + x + y; 73 | } 74 | 75 | // issue #373 76 | var foo = function(a, 77 | b) {}; 78 | 79 | // issue #350 80 | var foo = function*() { 81 | yield '123'; 82 | yield '456'; 83 | }; 84 | 85 | var foo = function*() { 86 | yield '123'; 87 | yield '456'; 88 | }; 89 | 90 | // issue #377 91 | let index = _.findLast(test, function(t) { 92 | return obj && obj[t] 93 | }) 94 | -------------------------------------------------------------------------------- /test/compare/default/function_expression-in.js: -------------------------------------------------------------------------------- 1 | var a=function( ){ return 'b';}; 2 | 3 | b = function doB(q,wer , ty ) { 4 | var c = function(n) { 5 | return function(){ return q + 6 | wer - ty; } 7 | } 8 | return c} 9 | 10 | this.foo = { 11 | bar : function(){ 12 | var r = function(){ 13 | re(); draw(); 14 | return log('foo') + 'bar';};}, 15 | ipsum : function ( amet ) { 16 | return function( ) { amet() } 17 | } 18 | }; 19 | 20 | var noop = function ( ) { 21 | 22 | }; 23 | 24 | 25 | var add = function(a, b) 26 | { 27 | return a + b; 28 | } 29 | 30 | call( function(a) 31 | { 32 | b(); 33 | } ); 34 | 35 | 36 | // issue #36 37 | var obj = { 38 | then: function( /* fnDone, fnFail, fnProgress */ ) { 39 | var fns = arguments; 40 | } 41 | }; 42 | 43 | 44 | // issue #134 45 | var foo = new MyConstructor(function otherFunction () { }); 46 | 47 | 48 | 49 | // issue #143 50 | if (!this._pollReceive) { 51 | this._pollReceive = nn.PollReceiveSocket(this.binding, function (events) { 52 | if (events) this._receive(); 53 | }.bind(this)); 54 | } 55 | 56 | // issue #283 57 | var foo = function foo () { 58 | bar() 59 | } 60 | 61 | var foo = function () { 62 | bar() 63 | } 64 | 65 | // default params (#285) 66 | var defaultParams = function defaults(z, x= 1, y = 2) { 67 | return z + x + y; 68 | } 69 | 70 | // issue #373 71 | var foo = function(a, 72 | b){}; 73 | 74 | // issue #350 75 | var foo = function * () { 76 | yield '123'; 77 | yield '456'; 78 | }; 79 | 80 | var foo = function*() { 81 | yield '123'; 82 | yield '456'; 83 | }; 84 | 85 | // issue #377 86 | let index = _.findLast(test, function (t) { 87 | return obj && obj[t] 88 | }) 89 | -------------------------------------------------------------------------------- /lib/hooks/ReturnStatement.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _tk = require('rocambole-token'); 4 | var _ws = require('rocambole-whitespace'); 5 | 6 | var expressionParentheses = require('./expressionParentheses'); 7 | 8 | 9 | exports.format = function ReturnStatement(node) { 10 | // need to make sure we only remove line breaks inside the node itself 11 | // because of ASI (see #29) 12 | var nonEmpty = _tk.findInBetween(node.startToken.next, node.endToken, _tk.isNotEmpty); 13 | // XXX: we want to remove line breaks and white spaces inside the node, not 14 | // using _br.limitAfter to avoid changing the program behavior (ASI) 15 | if (nonEmpty) _tk.removeEmptyInBetween(node.startToken, nonEmpty); 16 | 17 | _ws.limitAfter(node.startToken, 1); 18 | if (_tk.isSemiColon(node.endToken)) { 19 | // XXX: we want semicolon to be on same line and no whitespaces for now. 20 | _tk.removeEmptyInBetween(_tk.findPrevNonEmpty(node.endToken), node.endToken); 21 | } 22 | 23 | if (node.argument) { 24 | expressionParentheses.addSpaceInside(node.argument); 25 | } 26 | }; 27 | 28 | 29 | var _specialArguments = { 30 | 'BinaryExpression': true 31 | }; 32 | 33 | 34 | exports.getIndentEdges = function(node, opts) { 35 | // we bypass indentation if argument already adds indentation 36 | if (!node.argument || 37 | (opts[node.argument.type] && !_specialArguments[node.argument.type])) { 38 | return false; 39 | } 40 | 41 | var parentheses = expressionParentheses.getParentheses(node.argument); 42 | return parentheses ? 43 | { 44 | startToken: parentheses.opening, 45 | endToken: parentheses.closing 46 | } : 47 | { 48 | startToken: node.startToken.next, 49 | endToken: _tk.isEmpty(node.endToken) ? 50 | _tk.findPrevNonEmpty(node.endToken) : 51 | node.endToken 52 | }; 53 | }; 54 | -------------------------------------------------------------------------------- /lib/hooks/ArrayExpression.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _tk = require('rocambole-token'); 4 | var _limit = require('../limit'); 5 | 6 | 7 | exports.format = function ArrayExpression(node) { 8 | if (node.elements.length) { 9 | _limit.around(node.startToken, 'ArrayExpressionOpening'); 10 | _limit.around(node.endToken, 'ArrayExpressionClosing'); 11 | 12 | node.elements.forEach(function(el) { 13 | // sparse arrays have `null` elements 14 | if (!el) return; 15 | 16 | var prev = _tk.findPrevNonEmpty(el.startToken); 17 | if (prev.value === ',') { 18 | _limit.around(prev, 'ArrayExpressionComma'); 19 | } 20 | }); 21 | } else { 22 | // empty array should be single line 23 | _limit.after(node.startToken, 0); 24 | } 25 | }; 26 | 27 | 28 | exports.getIndentEdges = function(node) { 29 | var start; 30 | var prev = node.startToken; 31 | 32 | // this will grab the start of first element that is on a new line 33 | node.elements.some(function(el, i, els) { 34 | // sparse arrays have `null` elements! which is very weird 35 | if (i) { 36 | var prevEl = els[i - 1]; 37 | prev = prevEl ? prevEl.endToken : _tk.findNextNonEmpty(prev); 38 | } 39 | var next = el ? el.startToken : _tk.findNextNonEmpty(prev); 40 | 41 | if (_tk.findInBetween(prev, next, _tk.isBr)) { 42 | start = prev; 43 | return true; 44 | } 45 | }); 46 | 47 | var end = node.endToken.prev; 48 | 49 | // if it ends on same line as previous non-empty we need to change the indent 50 | // rule to make sure {}, [] and () are aligned 51 | var sibling = _tk.findPrevNonEmpty(node.endToken); 52 | if (!_tk.findInBetween(sibling, node.endToken, _tk.isBr)) { 53 | end = node.endToken; 54 | } 55 | 56 | return start ? { 57 | startToken: start, 58 | endToken: end 59 | } : false; 60 | }; 61 | 62 | -------------------------------------------------------------------------------- /lib/preset/jquery.json: -------------------------------------------------------------------------------- 1 | { 2 | "preset" : "default", 3 | 4 | "indent" : { 5 | "value" : "\t", 6 | "IfStatementConditional": 2, 7 | "SwitchStatement" : 0, 8 | "TopLevelFunctionBlock" : 0 9 | }, 10 | 11 | "lineBreak" : { 12 | "before" : { 13 | "ObjectExpressionOpeningBrace": -1, 14 | "ObjectExpressionClosingBrace": -1, 15 | "Property": -1, 16 | "VariableDeclarationWithoutInit" : 0 17 | }, 18 | 19 | "after": { 20 | "AssignmentOperator": -1, 21 | "ObjectExpressionOpeningBrace": -1, 22 | "ObjectExpressionClosingBrace": -1, 23 | "Property": -1 24 | } 25 | }, 26 | 27 | "whiteSpace" : { 28 | "before" : { 29 | "ArgumentList" : 1, 30 | "ArrayExpressionClosing" : 1, 31 | "CatchParameterList": 1, 32 | "ExpressionClosingParentheses" : 1, 33 | "ForInStatementExpressionClosing" : 1, 34 | "ForOfStatementExpressionClosing" : 1, 35 | "ForStatementExpressionClosing" : 1, 36 | "IfStatementConditionalClosing" : 1, 37 | "IIFEClosingParentheses": 1, 38 | "MemberExpressionClosing" : 1, 39 | "ObjectExpressionClosingBrace": 1, 40 | "ParameterList" : 1, 41 | "SwitchDiscriminantClosing" : 1, 42 | "WhileStatementConditionalClosing" : 1 43 | }, 44 | "after" : { 45 | "ArgumentList" : 1, 46 | "ArrayExpressionOpening" : 1, 47 | "CatchParameterList": 1, 48 | "ExpressionOpeningParentheses" : 1, 49 | "ForInStatementExpressionOpening" : 1, 50 | "ForOfStatementExpressionOpening" : 1, 51 | "ForStatementExpressionOpening" : 1, 52 | "IfStatementConditionalOpening" : 1, 53 | "IIFEOpeningParentheses": 1, 54 | "MemberExpressionOpening" : 1, 55 | "ObjectExpressionOpeningBrace": 1, 56 | "ParameterList" : 1, 57 | "PropertyValue": -1, 58 | "SwitchDiscriminantOpening" : 1, 59 | "WhileStatementConditionalOpening" : 1 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /test/compare/custom/try_statement-in.js: -------------------------------------------------------------------------------- 1 | try{foo()} catch (e){ log(e) 2 | } 3 | 4 | try 5 | { 6 | // foo comment 7 | foo(); 8 | } 9 | finally 10 | { 11 | // bar comment 12 | bar(); 13 | } 14 | 15 | try{foo()} catch (e){ log(e) 16 | } finally { 17 | bar() 18 | } 19 | 20 | try { 21 | bar( "foo" ); 22 | } catch ( e ) { 23 | // Empty Catch comment 24 | } 25 | 26 | 27 | // issue #35: "catch" block indent + empty catch body 28 | jQuery.ready.promise = function( obj ) { 29 | try { 30 | top = window.frameElement == null && document.documentElement; 31 | } catch(e) {} 32 | }; 33 | 34 | // "catch" brace indent 35 | function issueNN( obj ) { 36 | try { 37 | x = y; 38 | } catch (e) { 39 | console.log(e); 40 | } 41 | } 42 | 43 | // "finally" brace indent 44 | function foo(obj) { 45 | try { 46 | top = window.frameElement == null && document.documentElement; 47 | } catch (e) { 48 | console.log(e); 49 | } finally { 50 | // finally a comment 51 | top = 0; 52 | // weird 53 | } 54 | } 55 | 56 | jQuery.ready.promise = function( obj ) { 57 | try{ 58 | // try 2 59 | top = window.frameElement == null && document.documentElement; 60 | // try after 2 61 | }catch(e){ 62 | // catch 2 63 | console.log(e); 64 | // catch after 2 65 | }finally{ 66 | // finally a comment 2 67 | top = 0; 68 | // finally after 2 69 | } 70 | }; 71 | 72 | // nested try-catch 73 | function nestedTryCatch() { 74 | try{ 75 | normalPath(); 76 | }catch(e) { 77 | try { 78 | // try 79 | alternatePath(); 80 | // just a little bit harder 81 | } catch(e){ 82 | // catch 83 | console.log(e); 84 | // if you can 85 | }finally{} 86 | }finally{ shouldBreak = true; } next(); 87 | } 88 | 89 | // line break handling (#128) 90 | try { 91 | doStuff() 92 | } 93 | catch 94 | (e) 95 | { 96 | yesThisIsWeird() 97 | } 98 | -------------------------------------------------------------------------------- /test/compare/default/function_declaration-in.js: -------------------------------------------------------------------------------- 1 | function simple(x,y){return x+y;} 2 | 3 | function simple_2(a,b,c) 4 | { 5 | return a+b + c ; 6 | } 7 | 8 | // indent, spaces 9 | function foo( x ){ return x; } 10 | 11 | // test space on params 12 | function bar(a,b,c){ 13 | // test indentation 14 | return 'baz'; // test comment 15 | } 16 | 17 | // test nested fn 18 | function dolor(){ 19 | // trailing white space 20 | // missing semicolon 21 | function fn(){ function deep() { 22 | // moar 23 | function moar() { 24 | // nested comment 25 | return "inner"; 26 | } 27 | return moar( ) ; 28 | } 29 | // test invocation 30 | setTimeout(fn,100); 31 | } 32 | } 33 | 34 | // invocation 35 | dolor(); 36 | 37 | 38 | // start test keepEmptyLines 39 | 40 | 41 | 42 | // end test keepEmptyLines 43 | 44 | // test a bug related with indentation and multiple consecutive functions 45 | function outter(){ function a1(){return true}function a2(val){return (val*2)} } 46 | 47 | 48 | // issue #29 : return + line break + ternary 49 | function iss29(a){ 50 | return 51 | a<5?23:12; 52 | } 53 | 54 | function multiLineReturn() { 55 | return a&& 56 | b|| 57 | c; 58 | } 59 | 60 | function expressionReturn() { 61 | return ( 62 | a && 63 | b+ 64 | c 65 | ); 66 | } 67 | 68 | // issue #283 69 | function foo () { 70 | bar() 71 | } 72 | 73 | // issue #140 74 | function chainedReturn() { 75 | return deferred.promise 76 | .then(console.log) 77 | } 78 | 79 | // issue #231 80 | function multiLineParams( 81 | foo, 82 | bar 83 | ) { 84 | } 85 | 86 | // issue #285 87 | function defaultParams(z, x = 1, y=2) { 88 | return x + y + z; 89 | } 90 | 91 | // issue #350 92 | function * gen() { 93 | yield '123'; 94 | yield '456'; 95 | } 96 | function* gen() { 97 | yield '123'; 98 | yield '456'; 99 | } 100 | function*gen() { 101 | yield '123'; 102 | yield '456'; 103 | } 104 | -------------------------------------------------------------------------------- /lib/hooks/Params.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // Important: Params is a "virtual" node type, not part of the AST spec. 4 | // this hook is actually called by FunctionDeclaration and FunctionExpression 5 | // hooks. It's mainly a way to share the common logic between both hooks. 6 | 7 | var _ws = require('rocambole-whitespace'); 8 | var _tk = require('rocambole-token'); 9 | var _limit = require('../limit'); 10 | 11 | 12 | exports.format = function Params(node) { 13 | var params = node.params; 14 | var opening = node.startToken.value === '(' ? 15 | node.startToken : 16 | _tk.findNext(node.startToken, '('); 17 | var closing = _tk.findPrev(node.body.startToken, ')'); 18 | 19 | if (params.length) { 20 | _ws.limitBefore(_tk.findNextNonEmpty(opening), 'ParameterList'); 21 | params.forEach(function(param, i) { 22 | // if only one param or last one there are no commas to look for 23 | if (i < params.length - 1) { 24 | _limit.around(_tk.findNext(param.startToken, ','), 'ParameterComma'); 25 | } 26 | 27 | // Default parameters are AssignmentExpressions as params 28 | if (param.type === 'AssignmentPattern' && param.right) { 29 | _limit.around(_tk.findPrev(param.right.startToken, '='), 'AssignmentPattern'); 30 | } 31 | }); 32 | _ws.limitAfter(_tk.findPrevNonEmpty(closing), 'ParameterList'); 33 | } else { 34 | _limit.after(opening, 0); 35 | } 36 | }; 37 | 38 | exports.getIndentEdges = function(node, opts) { 39 | var params = node.params; 40 | if (params.length && opts.ParameterList) { 41 | // get/set on ObjectEpression affect drastically the FunctionExpression 42 | // structure so we need to handle it differently 43 | var start = node.parent.type === 'Property' ? 44 | node.parent.startToken : 45 | node.startToken; 46 | return { 47 | // we check if start is equal to "(" because of arrow functions 48 | startToken: start.value === '(' ? start : _tk.findNext(start, '('), 49 | endToken: _tk.findPrev(node.body.startToken, ')'), 50 | level: opts.ParameterList 51 | }; 52 | } 53 | return null; 54 | }; 55 | -------------------------------------------------------------------------------- /test/compare/default/function_declaration-out.js: -------------------------------------------------------------------------------- 1 | function simple(x, y) { 2 | return x + y; 3 | } 4 | 5 | function simple_2(a, b, c) { 6 | return a + b + c; 7 | } 8 | 9 | // indent, spaces 10 | function foo(x) { 11 | return x; 12 | } 13 | 14 | // test space on params 15 | function bar(a, b, c) { 16 | // test indentation 17 | return 'baz'; // test comment 18 | } 19 | 20 | // test nested fn 21 | function dolor() { 22 | // trailing white space 23 | // missing semicolon 24 | function fn() { 25 | function deep() { 26 | // moar 27 | function moar() { 28 | // nested comment 29 | return "inner"; 30 | } 31 | return moar(); 32 | } 33 | // test invocation 34 | setTimeout(fn, 100); 35 | } 36 | } 37 | 38 | // invocation 39 | dolor(); 40 | 41 | 42 | // start test keepEmptyLines 43 | 44 | 45 | 46 | // end test keepEmptyLines 47 | 48 | // test a bug related with indentation and multiple consecutive functions 49 | function outter() { 50 | function a1() { 51 | return true 52 | } 53 | function a2(val) { 54 | return (val * 2) 55 | } 56 | } 57 | 58 | 59 | // issue #29 : return + line break + ternary 60 | function iss29(a) { 61 | return 62 | a < 5 ? 23 : 12; 63 | } 64 | 65 | function multiLineReturn() { 66 | return a && 67 | b || 68 | c; 69 | } 70 | 71 | function expressionReturn() { 72 | return ( 73 | a && 74 | b + 75 | c 76 | ); 77 | } 78 | 79 | // issue #283 80 | function foo() { 81 | bar() 82 | } 83 | 84 | // issue #140 85 | function chainedReturn() { 86 | return deferred.promise 87 | .then(console.log) 88 | } 89 | 90 | // issue #231 91 | function multiLineParams( 92 | foo, 93 | bar 94 | ) { 95 | } 96 | 97 | // issue #285 98 | function defaultParams(z, x = 1, y = 2) { 99 | return x + y + z; 100 | } 101 | 102 | // issue #350 103 | function* gen() { 104 | yield '123'; 105 | yield '456'; 106 | } 107 | function* gen() { 108 | yield '123'; 109 | yield '456'; 110 | } 111 | function* gen() { 112 | yield '123'; 113 | yield '456'; 114 | } 115 | -------------------------------------------------------------------------------- /test/compare/default/try_statement-out.js: -------------------------------------------------------------------------------- 1 | try { 2 | foo() 3 | } catch (e) { 4 | log(e) 5 | } 6 | 7 | try { 8 | // foo comment 9 | foo(); 10 | } finally { 11 | // bar comment 12 | bar(); 13 | } 14 | 15 | try { 16 | foo() 17 | } catch (e) { 18 | log(e) 19 | } finally { 20 | bar() 21 | } 22 | 23 | try { 24 | bar("foo"); 25 | } catch (e) { 26 | // Empty Catch comment 27 | } 28 | 29 | 30 | // issue #35: "catch" block indent + empty catch body 31 | jQuery.ready.promise = function(obj) { 32 | try { 33 | top = window.frameElement == null && document.documentElement; 34 | } catch (e) {} 35 | }; 36 | 37 | // "catch" brace indent 38 | function issueNN(obj) { 39 | try { 40 | x = y; 41 | } catch (e) { 42 | console.log(e); 43 | } 44 | } 45 | 46 | // "finally" brace indent 47 | function foo(obj) { 48 | try { 49 | top = window.frameElement == null && document.documentElement; 50 | } catch (e) { 51 | console.log(e); 52 | } finally { 53 | // finally a comment 54 | top = 0; 55 | // weird 56 | } 57 | } 58 | 59 | jQuery.ready.promise = function(obj) { 60 | try { 61 | // try 2 62 | top = window.frameElement == null && document.documentElement; 63 | // try after 2 64 | } catch (e) { 65 | // catch 2 66 | console.log(e); 67 | // catch after 2 68 | } finally { 69 | // finally a comment 2 70 | top = 0; 71 | // finally after 2 72 | } 73 | }; 74 | 75 | // nested try-catch 76 | function nestedTryCatch() { 77 | try { 78 | normalPath(); 79 | } catch (e) { 80 | try { 81 | // try 82 | alternatePath(); 83 | // just a little bit harder 84 | } catch (e) { 85 | // catch 86 | console.log(e); 87 | // if you can 88 | } finally {} 89 | } finally { 90 | shouldBreak = true; 91 | } 92 | next(); 93 | } 94 | 95 | // line break handling (#128) 96 | try { 97 | doStuff() 98 | } catch (e) { 99 | yesThisIsWeird() 100 | } 101 | 102 | // comment alignment (#270) 103 | try { 104 | bla(); 105 | // comment 106 | // too 107 | } catch (e) { 108 | throw e; 109 | } 110 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "esformatter", 3 | "version": "0.9.0", 4 | "description": "ECMAScript code beautifier/formatter", 5 | "main": "lib/esformatter.js", 6 | "bin": { 7 | "esformatter": "./bin/esformatter" 8 | }, 9 | "scripts": { 10 | "test": "node test/runner.js", 11 | "lint": "jshint lib/*.js lib/**/*.js test/*.js", 12 | "format": "esformatter -i 'lib/**/*.js'" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/millermedeiros/esformatter.git" 17 | }, 18 | "bugs": { 19 | "url": "https://github.com/millermedeiros/esformatter/issues" 20 | }, 21 | "directories": { 22 | "doc": "./doc", 23 | "bin": "./bin", 24 | "lib": "./lib" 25 | }, 26 | "keywords": [ 27 | "babel", 28 | "beautifier", 29 | "beautify", 30 | "ecmascript", 31 | "esprima", 32 | "format", 33 | "formatter", 34 | "javascript", 35 | "jscs", 36 | "source", 37 | "style", 38 | "syntax" 39 | ], 40 | "author": { 41 | "name": "Miller Medeiros", 42 | "url": "http://blog.millermedeiros.com/" 43 | }, 44 | "devDependencies": { 45 | "chai": "1.4", 46 | "esformatter-pipe-test": "file:test/pipe", 47 | "esformatter-test-plugin": "file:test/plugin", 48 | "jshint": "~2.3.0", 49 | "mocha": "https://github.com/millermedeiros/mocha/tarball/latest", 50 | "mockery": "^1.4.0" 51 | }, 52 | "dependencies": { 53 | "acorn-to-esprima": "^2.0.6", 54 | "babel-traverse": "^6.4.5", 55 | "babylon": "^6.4.5", 56 | "debug": "^0.7.4", 57 | "disparity": "^2.0.0", 58 | "glob": "^5.0.3", 59 | "minimist": "^1.1.1", 60 | "mout": ">=0.9 <2.0", 61 | "npm-run": "^2.0.0", 62 | "resolve": "^1.1.5", 63 | "rocambole": ">=0.7 <2.0", 64 | "rocambole-indent": "^2.0.4", 65 | "rocambole-linebreak": "^1.0.0", 66 | "rocambole-node": "~1.0", 67 | "rocambole-token": "^1.1.2", 68 | "rocambole-whitespace": "^1.0.0", 69 | "stdin": "*", 70 | "strip-json-comments": "~0.1.1", 71 | "supports-color": "^1.3.1", 72 | "user-home": "^2.0.0" 73 | }, 74 | "esformatter": { 75 | "root": true 76 | }, 77 | "license": "MIT" 78 | } 79 | -------------------------------------------------------------------------------- /test/compare/jquery/spacing-in.js: -------------------------------------------------------------------------------- 1 | // this file is imcomplete since jquery style guide support is still not 2 | // finished (see #19) 3 | 4 | var i = 0; 5 | 6 | if (condition) { doSomething(); } else if (otherCondition) { 7 | somethingElse(); 8 | // comment 9 | } else { 10 | // comment 11 | otherThing(); 12 | } 13 | 14 | this.element 15 | .add() 16 | .set({ 17 | // line comment 18 | // one more 19 | prop: "value" 20 | }); 21 | 22 | while (x) { 23 | y(); 24 | } 25 | 26 | for (i = 0; i < length; i++) { 27 | y(); 28 | } 29 | for ( ; i < length; i++ ) { 30 | y(); 31 | } 32 | 33 | function x() { 34 | return something && 35 | !somethingElse; 36 | } 37 | 38 | ul.outerWidth( Math.max( 39 | // Firefox wraps long text (possibly a rounding bug) 40 | // so we add 1px to avoid the wrapping (#7513) 41 | ul.width( "" ).outerWidth() + 1, 42 | this.element.outerWidth() 43 | ) ); 44 | 45 | function x() { 46 | return this.indeterminate ? false : 47 | Math.min( this.options.max, Math.max( this.min, newValue ) ); 48 | } 49 | 50 | if ( event.target !== that.element[ 0 ] && 51 | event.target !== menuElement && 52 | !$.contains( menuElement, event.target ) ) { 53 | close(); 54 | } 55 | 56 | contents = this.headers.next() 57 | .removeClass("ui-helper-reset ui-widget-content ui-corner-bottom " + 58 | "ui-accordion-content ui-accordion-content-active ui-state-disabled") 59 | .css("display", "") 60 | .removeAttr("role"); 61 | 62 | this.buttonElement 63 | .addClass( baseClasses ) 64 | .bind( "click" + this.eventNamespace, function( event ) { 65 | if ( options.disabled ) { 66 | event.preventDefault(); 67 | } 68 | }); 69 | 70 | try { 71 | x(); 72 | } catch(error) { 73 | console.log(error); 74 | } 75 | 76 | x({ a: 1 }); 77 | y({ 78 | a: 1 79 | }); 80 | $.each( { div: "#list1", ul: "#navigation", dl: "#accordion-dl" } ); 81 | 82 | (function($) { 83 | x; 84 | }(jQuery)); 85 | 86 | var x = {foo:{bar: true}}; 87 | var y = {a: b, c: d, e:{ f: g}}; 88 | x = { 89 | props: { 90 | // comment 91 | x: 1 92 | } 93 | }; 94 | x={ 95 | b:function b() { 96 | a(); 97 | }, 98 | a:b 99 | }; 100 | -------------------------------------------------------------------------------- /test/compare/jquery/spacing-out.js: -------------------------------------------------------------------------------- 1 | // this file is imcomplete since jquery style guide support is still not 2 | // finished (see #19) 3 | 4 | var i = 0; 5 | 6 | if ( condition ) { 7 | doSomething(); 8 | } else if ( otherCondition ) { 9 | somethingElse(); 10 | // comment 11 | } else { 12 | // comment 13 | otherThing(); 14 | } 15 | 16 | this.element 17 | .add() 18 | .set( { 19 | // line comment 20 | // one more 21 | prop: "value" 22 | } ); 23 | 24 | while ( x ) { 25 | y(); 26 | } 27 | 28 | for ( i = 0; i < length; i++ ) { 29 | y(); 30 | } 31 | for ( ; i < length; i++ ) { 32 | y(); 33 | } 34 | 35 | function x() { 36 | return something && 37 | !somethingElse; 38 | } 39 | 40 | ul.outerWidth( Math.max( 41 | // Firefox wraps long text (possibly a rounding bug) 42 | // so we add 1px to avoid the wrapping (#7513) 43 | ul.width( "" ).outerWidth() + 1, 44 | this.element.outerWidth() 45 | ) ); 46 | 47 | function x() { 48 | return this.indeterminate ? false : 49 | Math.min( this.options.max, Math.max( this.min, newValue ) ); 50 | } 51 | 52 | if ( event.target !== that.element[ 0 ] && 53 | event.target !== menuElement && 54 | !$.contains( menuElement, event.target ) ) { 55 | close(); 56 | } 57 | 58 | contents = this.headers.next() 59 | .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom " + 60 | "ui-accordion-content ui-accordion-content-active ui-state-disabled" ) 61 | .css( "display", "" ) 62 | .removeAttr( "role" ); 63 | 64 | this.buttonElement 65 | .addClass( baseClasses ) 66 | .bind( "click" + this.eventNamespace, function( event ) { 67 | if ( options.disabled ) { 68 | event.preventDefault(); 69 | } 70 | } ); 71 | 72 | try { 73 | x(); 74 | } catch ( error ) { 75 | console.log( error ); 76 | } 77 | 78 | x( { a: 1 } ); 79 | y( { 80 | a: 1 81 | } ); 82 | $.each( { div: "#list1", ul: "#navigation", dl: "#accordion-dl" } ); 83 | 84 | ( function( $ ) { 85 | x; 86 | }( jQuery ) ); 87 | 88 | var x = { foo: { bar: true } }; 89 | var y = { a: b, c: d, e: { f: g } }; 90 | x = { 91 | props: { 92 | // comment 93 | x: 1 94 | } 95 | }; 96 | x = { 97 | b: function b() { 98 | a(); 99 | }, 100 | a: b 101 | }; 102 | -------------------------------------------------------------------------------- /test/compare/default/try_statement-in.js: -------------------------------------------------------------------------------- 1 | try{foo()} catch (e){ log(e) 2 | } 3 | 4 | try 5 | { 6 | // foo comment 7 | foo(); 8 | } 9 | finally 10 | { 11 | // bar comment 12 | bar(); 13 | } 14 | 15 | try{foo()} catch (e){ log(e) 16 | } finally { 17 | bar() 18 | } 19 | 20 | try { 21 | bar( "foo" ); 22 | } catch ( e ) { 23 | // Empty Catch comment 24 | } 25 | 26 | 27 | // issue #35: "catch" block indent + empty catch body 28 | jQuery.ready.promise = function( obj ) { 29 | try { 30 | top = window.frameElement == null && document.documentElement; 31 | } catch(e) {} 32 | }; 33 | 34 | // "catch" brace indent 35 | function issueNN( obj ) { 36 | try { 37 | x = y; 38 | } catch (e) { 39 | console.log(e); 40 | } 41 | } 42 | 43 | // "finally" brace indent 44 | function foo(obj) { 45 | try { 46 | top = window.frameElement == null && document.documentElement; 47 | } catch (e) { 48 | console.log(e); 49 | } finally { 50 | // finally a comment 51 | top = 0; 52 | // weird 53 | } 54 | } 55 | 56 | jQuery.ready.promise = function( obj ) { 57 | try{ 58 | // try 2 59 | top = window.frameElement == null && document.documentElement; 60 | // try after 2 61 | }catch(e){ 62 | // catch 2 63 | console.log(e); 64 | // catch after 2 65 | }finally{ 66 | // finally a comment 2 67 | top = 0; 68 | // finally after 2 69 | } 70 | }; 71 | 72 | // nested try-catch 73 | function nestedTryCatch() { 74 | try{ 75 | normalPath(); 76 | }catch(e) { 77 | try { 78 | // try 79 | alternatePath(); 80 | // just a little bit harder 81 | } catch(e){ 82 | // catch 83 | console.log(e); 84 | // if you can 85 | }finally{} 86 | }finally{ shouldBreak = true; } next(); 87 | } 88 | 89 | // line break handling (#128) 90 | try { 91 | doStuff() 92 | } 93 | catch 94 | (e) 95 | { 96 | yesThisIsWeird() 97 | } 98 | 99 | // comment alignment (#270) 100 | try { 101 | bla(); 102 | // comment 103 | // too 104 | } catch(e) { 105 | throw e; 106 | } 107 | -------------------------------------------------------------------------------- /test/compare/custom/try_statement-out.js: -------------------------------------------------------------------------------- 1 | try 2 | { 3 | foo() 4 | } 5 | catch (e) 6 | { 7 | log(e) 8 | } 9 | 10 | try 11 | { 12 | // foo comment 13 | foo(); 14 | } 15 | finally 16 | { 17 | // bar comment 18 | bar(); 19 | } 20 | 21 | try 22 | { 23 | foo() 24 | } 25 | catch (e) 26 | { 27 | log(e) 28 | } 29 | finally 30 | { 31 | bar() 32 | } 33 | 34 | try 35 | { 36 | bar("foo"); 37 | } 38 | catch (e) 39 | { 40 | // Empty Catch comment 41 | } 42 | 43 | 44 | // issue #35: "catch" block indent + empty catch body 45 | jQuery.ready.promise = function(obj) { 46 | try 47 | { 48 | top = window.frameElement == null && document.documentElement; 49 | } 50 | catch (e) 51 | {} 52 | }; 53 | 54 | // "catch" brace indent 55 | function issueNN(obj) { 56 | try 57 | { 58 | x = y; 59 | } 60 | catch (e) 61 | { 62 | console.log(e); 63 | } 64 | } 65 | 66 | // "finally" brace indent 67 | function foo(obj) { 68 | try 69 | { 70 | top = window.frameElement == null && document.documentElement; 71 | } 72 | catch (e) 73 | { 74 | console.log(e); 75 | } 76 | finally 77 | { 78 | // finally a comment 79 | top = 0; 80 | // weird 81 | } 82 | } 83 | 84 | jQuery.ready.promise = function(obj) { 85 | try 86 | { 87 | // try 2 88 | top = window.frameElement == null && document.documentElement; 89 | // try after 2 90 | } 91 | catch (e) 92 | { 93 | // catch 2 94 | console.log(e); 95 | // catch after 2 96 | } 97 | finally 98 | { 99 | // finally a comment 2 100 | top = 0; 101 | // finally after 2 102 | } 103 | }; 104 | 105 | // nested try-catch 106 | function nestedTryCatch() { 107 | try 108 | { 109 | normalPath(); 110 | } 111 | catch (e) 112 | { 113 | try 114 | { 115 | // try 116 | alternatePath(); 117 | // just a little bit harder 118 | } 119 | catch (e) 120 | { 121 | // catch 122 | console.log(e); 123 | // if you can 124 | } 125 | finally 126 | {} 127 | } 128 | finally 129 | { 130 | shouldBreak = true; 131 | } 132 | next(); 133 | } 134 | 135 | // line break handling (#128) 136 | try 137 | { 138 | doStuff() 139 | } 140 | catch (e) 141 | { 142 | yesThisIsWeird() 143 | } 144 | -------------------------------------------------------------------------------- /lib/hooks/FunctionExpression.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _tk = require('rocambole-token'); 4 | var _ws = require('rocambole-whitespace'); 5 | var _params = require('./Params'); 6 | var _limit = require('../limit'); 7 | 8 | 9 | exports.format = function FunctionExpression(node) { 10 | _limit.around(node.body.startToken, 'FunctionExpressionOpeningBrace'); 11 | _limit.around(node.endToken, 'FunctionExpressionClosingBrace'); 12 | 13 | var startToken = node.startToken; 14 | if (node.id) { 15 | _ws.limit(node.id.startToken, 'FunctionName'); 16 | } else if (startToken.value === 'function') { 17 | if (node.generator) { 18 | startToken = _tk.findNextNonEmpty(startToken); 19 | _ws.limitBefore(startToken, 'FunctionGeneratorAsterisk'); 20 | } 21 | 22 | _ws.limit(startToken, 'FunctionReservedWord'); 23 | } 24 | 25 | if (_tk.isWs(node.endToken.next) && 26 | _tk.isSemiColon(node.endToken.next.next)) { 27 | _tk.remove(node.endToken.next); 28 | } 29 | 30 | if (node.parent.type === 'CallExpression') { 31 | _ws.limitAfter(node.endToken, 0); 32 | } 33 | 34 | var bodyFirstNonEmpty = _tk.findNextNonEmpty(node.body.startToken); 35 | if (bodyFirstNonEmpty.value === '}') { 36 | // noop 37 | _limit.after(node.body.startToken, 0); 38 | } 39 | 40 | _params.format(node); 41 | }; 42 | 43 | 44 | exports.getIndentEdges = function(node, opts) { 45 | var params = _params.getIndentEdges(node, opts); 46 | // TODO make this a plugin 47 | if (!opts.TopLevelFunctionBlock && isTopLevelFunctionBlock(node)) { 48 | return params; 49 | } 50 | return [ 51 | params, 52 | { 53 | startToken: node.body.startToken, 54 | endToken: _tk.findPrevNonEmpty(node.body.endToken).next 55 | } 56 | ]; 57 | }; 58 | 59 | 60 | function isTopLevelFunctionBlock(node) { 61 | // exception for UMD blocks 62 | return !(node.params.length === 1 && node.params[0].name === "factory") && 63 | // regular IFEE 64 | (isOfType(node.parent, 'CallExpression') || 65 | // module.exports assignment 66 | isOfType(node.parent, 'AssignmentExpression')) && 67 | !isOfType(node.parent.callee, 'MemberExpression') && 68 | isOfType(node.parent.parent, 'ExpressionStatement') && 69 | isOfType(node.parent.parent.parent, 'Program'); 70 | } 71 | 72 | 73 | // TODO: extract into rocambole-node 74 | function isOfType(node, type) { 75 | return node && node.type === type; 76 | } 77 | -------------------------------------------------------------------------------- /lib/plugins.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var partial = require('mout/function/partial'); 4 | var remove = require('mout/array/remove'); 5 | 6 | var _plugins = []; 7 | 8 | 9 | exports.register = register; 10 | function register(plugin) { 11 | if (_plugins.indexOf(plugin) === -1) { 12 | _plugins.push(plugin); 13 | } 14 | } 15 | 16 | 17 | exports.unregister = partial(remove, _plugins); 18 | 19 | 20 | exports.unregisterAll = unregisterAll; 21 | function unregisterAll() { 22 | _plugins = []; 23 | } 24 | 25 | 26 | exports.setOptions = function(opts) { 27 | loadAndRegister(opts && opts.plugins); 28 | // esformatter ends up being a circular dependency, 29 | // but this was the quickest way of doing it :P 30 | // needed specially because of issue #348 31 | exec('setOptions', opts, require('./esformatter')); 32 | }; 33 | 34 | 35 | exports.loadAndRegister = loadAndRegister; 36 | function loadAndRegister(ids) { 37 | ids = ids || []; 38 | ids.forEach(function(id) { 39 | var module; 40 | try { 41 | module = require(id); 42 | } catch (e) { 43 | throw new Error( 44 | 'Error: Cannot find plugin \'' + id + '\'.' + ' Make sure ' + 45 | 'you used the correct name on the config file or run `npm install ' + 46 | '--save-dev ' + id + '` to add it as a project dependency.' 47 | ); 48 | } 49 | register(module); 50 | }); 51 | } 52 | 53 | 54 | exportMethods([ 55 | 'tokenBefore', 56 | 'tokenAfter', 57 | 'nodeBefore', 58 | 'nodeAfter', 59 | // "transform" is an alias to "transformAfter" but we do not recommend using 60 | // it going forward. it might be deprecated in the future. 61 | 'transform', 62 | 'transformAfter', 63 | 'transformBefore' 64 | ], exec); 65 | 66 | exportMethods([ 67 | 'stringBefore', 68 | 'stringAfter' 69 | ], pipe); 70 | 71 | 72 | function exportMethods(arr, fn) { 73 | arr.forEach(function(methodName) { 74 | exports[methodName] = partial(fn, methodName); 75 | }); 76 | } 77 | 78 | 79 | function exec(methodName) { 80 | var args = Array.prototype.slice.call(arguments, 1); 81 | _plugins.forEach(function(plugin) { 82 | if (methodName in plugin) { 83 | plugin[methodName].apply(plugin, args); 84 | } 85 | }); 86 | } 87 | 88 | 89 | function pipe(methodName, input) { 90 | return _plugins.reduce(function(output, plugin) { 91 | return methodName in plugin ? plugin[methodName](output) : output; 92 | }, input); 93 | } 94 | -------------------------------------------------------------------------------- /test/compare/default/call_expression-out.js: -------------------------------------------------------------------------------- 1 | foo(); 2 | baz(); 3 | 4 | bar(1, 'dolor'); 5 | ipsum(3, { 6 | amet: true 7 | }, 'foo'); 8 | 9 | dolor = foo(2) 10 | 11 | // should not remove line breaks 12 | foo(a, b, 13 | c, d) 14 | 15 | tricky((123)); 16 | tricky2((123), ((456))); 17 | 18 | // it should indent chained calls if there is a line break between each call 19 | foo.bar() 20 | // comment 21 | .ipsum() 22 | .dolor(); 23 | 24 | function foo() { 25 | dolor 26 | // comment 27 | .amet() 28 | .maecennas(); 29 | } 30 | 31 | contents = this.headers.next() 32 | .removeClass("ui-helper-reset ui-widget-content ui-corner-bottom " + 33 | "ui-accordion-content ui-accordion-content-active ui-state-disabled") 34 | .css("display", "") 35 | .removeAttr("role"); 36 | 37 | returned.promise().done(foo) 38 | // comment 39 | .done(newDefer.resolve) 40 | .fail(newDefer.reject) 41 | // comment 42 | .progress(newDefer.notify); 43 | 44 | filter(function() { 45 | // comment 46 | x; 47 | }).map(function() { 48 | // comment 49 | y; 50 | }); 51 | 52 | var contents; 53 | contents = this.headers.next() 54 | .removeClass("ui-state-disabled") 55 | .css("display", ""); 56 | 57 | gulp.task('lint', function() { 58 | return gulp.src('**.js') 59 | .pipe(jshint()) 60 | .pipe(jshint.reporter(stylish)); 61 | }); 62 | 63 | // issue #68 64 | define(function() { 65 | // line comment 66 | x; 67 | }); 68 | 69 | 70 | noArgs(); 71 | 72 | noArgs2(); 73 | noArgs3(); 74 | noArgs4( 75 | // not passing any args for some reason 76 | ); 77 | 78 | 79 | // only indent if there is a line break before/between arguments 80 | indent( 81 | 'foo' 82 | ); 83 | 84 | indent2({ 85 | dolor: 123 86 | }, [ 87 | 1, 2, 3 88 | ]); 89 | 90 | // this is a weird style but makes sense to indent args if you think about it 91 | indent3('lorem', 92 | { 93 | ipsum: 'dolor' 94 | }, 95 | [ 96 | 1, 97 | 2, 98 | 3 99 | ]); 100 | 101 | indent4({ 102 | a: b 103 | }); 104 | indent5( 105 | { 106 | a: b 107 | }, 108 | [1, 2, 3] 109 | ); 110 | indent6( 111 | { 112 | a: b 113 | }, [ 114 | 1, 2, 3 115 | ] 116 | ); 117 | 118 | 119 | // issue #200 120 | require([ 121 | "foo", 122 | "bar" 123 | ], function(foo, bar) { 124 | foo(bar); 125 | }); 126 | 127 | 128 | // issue #202 129 | app 130 | .directive('testDirective', ['param', 131 | function(param) { 132 | alert(); 133 | } 134 | ]) 135 | 136 | // issue #240 137 | equal( 138 | y 139 | .find() 140 | .length, 141 | expected 142 | ); 143 | 144 | // issue #252 145 | promise().then(function(foo) { 146 | return x; 147 | }, function(bar) { 148 | return y; 149 | }); 150 | 151 | // issue #267 152 | require('something'); 153 | var Sidebar = Backbone.Model.extend({ 154 | //... 155 | lorem: 'ipsum' 156 | }); 157 | 158 | // issue #306 159 | foo(!!(lorem || 160 | ipsum || dolor)); 161 | -------------------------------------------------------------------------------- /test/compare/default/call_expression-in.js: -------------------------------------------------------------------------------- 1 | foo(); 2 | baz(); 3 | 4 | bar(1,'dolor'); 5 | ipsum(3,{amet:true},'foo'); 6 | 7 | dolor=foo(2) 8 | 9 | // should not remove line breaks 10 | foo(a,b, 11 | c,d) 12 | 13 | tricky( (123) ); 14 | tricky2( (123) , ((456)) ); 15 | 16 | // it should indent chained calls if there is a line break between each call 17 | foo.bar() 18 | // comment 19 | .ipsum() 20 | .dolor(); 21 | 22 | function foo() { 23 | dolor 24 | // comment 25 | .amet() 26 | .maecennas(); 27 | } 28 | 29 | contents = this.headers.next() 30 | .removeClass("ui-helper-reset ui-widget-content ui-corner-bottom " + 31 | "ui-accordion-content ui-accordion-content-active ui-state-disabled") 32 | .css("display", "") 33 | .removeAttr("role"); 34 | 35 | returned.promise().done(foo) 36 | // comment 37 | .done(newDefer.resolve) 38 | .fail(newDefer.reject) 39 | // comment 40 | .progress(newDefer.notify); 41 | 42 | filter(function() { 43 | // comment 44 | x; 45 | }).map(function() { 46 | // comment 47 | y; 48 | }); 49 | 50 | var contents; 51 | contents = this.headers.next() 52 | .removeClass("ui-state-disabled") 53 | .css("display", ""); 54 | 55 | gulp.task('lint', function() { 56 | return gulp.src('**.js') 57 | .pipe(jshint()) 58 | .pipe(jshint.reporter(stylish)); 59 | }); 60 | 61 | // issue #68 62 | define(function() { 63 | // line comment 64 | x; 65 | }); 66 | 67 | 68 | noArgs( 69 | ); 70 | 71 | noArgs2( ); 72 | noArgs3(); 73 | noArgs4( 74 | // not passing any args for some reason 75 | ); 76 | 77 | 78 | // only indent if there is a line break before/between arguments 79 | indent( 80 | 'foo' 81 | ); 82 | 83 | indent2({ 84 | dolor: 123 85 | }, [ 86 | 1, 2, 3 87 | ]); 88 | 89 | // this is a weird style but makes sense to indent args if you think about it 90 | indent3('lorem', 91 | { 92 | ipsum: 'dolor' 93 | }, 94 | [ 95 | 1, 96 | 2, 97 | 3 98 | ]); 99 | 100 | indent4({ 101 | a: b 102 | }); 103 | indent5( 104 | { 105 | a: b 106 | }, 107 | [1, 2, 3] 108 | ); 109 | indent6( 110 | { 111 | a: b 112 | }, [ 113 | 1, 2, 3 114 | ] 115 | ); 116 | 117 | 118 | // issue #200 119 | require([ 120 | "foo", 121 | "bar" 122 | ], function (foo, bar) { 123 | foo(bar); 124 | }); 125 | 126 | 127 | // issue #202 128 | app 129 | .directive( 'testDirective', [ 'param', 130 | function( param ) { 131 | alert(); 132 | } 133 | ]) 134 | 135 | // issue #240 136 | equal( 137 | y 138 | .find() 139 | .length, 140 | expected 141 | ); 142 | 143 | // issue #252 144 | promise().then(function(foo) { 145 | return x; 146 | }, function(bar) { 147 | return y; 148 | }); 149 | 150 | // issue #267 151 | require ('something'); 152 | var Sidebar = Backbone.Model.extend 153 | ({ 154 | //... 155 | lorem: 'ipsum' 156 | }); 157 | 158 | // issue #306 159 | foo(!!(lorem || 160 | ipsum || dolor)); 161 | -------------------------------------------------------------------------------- /lib/hooks.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | 4 | // Hooks for each node.type that should be processed individually 5 | // --- 6 | // using an object to store each transform method to avoid a long switch 7 | // statement, will be more organized in the long run and also allow 8 | // monkey-patching/spies/mock/stub. 9 | 10 | 11 | // we are not using something like https://npmjs.org/package/require-all 12 | // because we want esformatter to be able to run in the browser in the future 13 | 14 | exports.ArrayExpression = require('./hooks/ArrayExpression'); 15 | exports.ArrayPattern = require('./hooks/ArrayPattern'); 16 | exports.ArrowFunctionExpression = require('./hooks/ArrowFunctionExpression'); 17 | exports.AssignmentExpression = require('./hooks/AssignmentExpression'); 18 | exports.BinaryExpression = require('./hooks/BinaryExpression'); 19 | exports.CallExpression = exports.NewExpression = require('./hooks/CallExpression'); 20 | exports.CatchClause = require('./hooks/CatchClause'); 21 | exports.ClassDeclaration = exports.ClassExpression = require('./hooks/ClassDeclarationAndExpression'); 22 | exports.ConditionalExpression = require('./hooks/ConditionalExpression'); 23 | exports.DoWhileStatement = require('./hooks/DoWhileStatement'); 24 | exports.ExportAllDeclaration = require('./hooks/ExportAllDeclaration'); 25 | exports.ExportDefaultDeclaration = require('./hooks/ExportDefaultDeclaration'); 26 | exports.ExportNamedDeclaration = require('./hooks/ExportNamedDeclaration'); 27 | exports.ExportSpecifier = require('./hooks/ExportSpecifier'); 28 | exports.ForInStatement = require('./hooks/ForInStatement'); 29 | exports.ForOfStatement = require('./hooks/ForOfStatement'); 30 | exports.ForStatement = require('./hooks/ForStatement'); 31 | exports.FunctionDeclaration = require('./hooks/FunctionDeclaration'); 32 | exports.FunctionExpression = require('./hooks/FunctionExpression'); 33 | exports.IfStatement = require('./hooks/IfStatement'); 34 | exports.ImportDeclaration = require('./hooks/ImportDeclaration'); 35 | exports.ImportSpecifier = require('./hooks/ImportSpecifier'); 36 | exports.LogicalExpression = require('./hooks/LogicalExpression'); 37 | exports.MemberExpression = require('./hooks/MemberExpression'); 38 | exports.MethodDefinition = require('./hooks/MethodDefinition'); 39 | exports.ObjectExpression = require('./hooks/ObjectExpression'); 40 | exports.ObjectPattern = require('./hooks/ObjectPattern'); 41 | exports.ReturnStatement = require('./hooks/ReturnStatement'); 42 | exports.SequenceExpression = require('./hooks/SequenceExpression'); 43 | exports.SwitchStatement = require('./hooks/SwitchStatement'); 44 | exports.SwitchCase = require('./hooks/SwitchCase'); 45 | exports.ThrowStatement = require('./hooks/ThrowStatement'); 46 | exports.TryStatement = require('./hooks/TryStatement'); 47 | exports.UnaryExpression = require('./hooks/UnaryExpression'); 48 | exports.UpdateExpression = require('./hooks/UpdateExpression'); 49 | exports.VariableDeclaration = require('./hooks/VariableDeclaration'); 50 | exports.WhileStatement = require('./hooks/WhileStatement'); 51 | -------------------------------------------------------------------------------- /lib/hooks/VariableDeclaration.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _br = require('rocambole-linebreak'); 4 | var _tk = require('rocambole-token'); 5 | var _ws = require('rocambole-whitespace'); 6 | var helpers = require('../helpers'); 7 | 8 | 9 | exports.format = function VariableDeclaration(node) { 10 | var insideFor = node.parent.type === 'ForStatement'; 11 | 12 | node.declarations.forEach(function(declarator, i) { 13 | var idStartToken = declarator.id.startToken; 14 | 15 | // need to swap comma-first line break 16 | var prevNonEmpty = _tk.findPrevNonEmpty(idStartToken); 17 | if (i && prevNonEmpty.value === ',') { 18 | if (_tk.isBr(prevNonEmpty.prev) || _tk.isBr(prevNonEmpty.prev.prev)) { 19 | var beforeComma = _tk.findPrev(prevNonEmpty, function(t) { 20 | return !_tk.isEmpty(t) && !_tk.isComment(t); 21 | }); 22 | _ws.limit(prevNonEmpty, 0); 23 | _tk.remove(prevNonEmpty); 24 | _tk.after(beforeComma, prevNonEmpty); 25 | } 26 | } 27 | 28 | if (!i && !_tk.isComment(_tk.findPrevNonEmpty(idStartToken))) { 29 | // XXX: we don't allow line breaks or multiple spaces after "var" 30 | // keyword for now (might change in the future) 31 | _tk.removeEmptyAdjacentBefore(idStartToken); 32 | } else if (!insideFor && declarator.init) { 33 | _br.limit(idStartToken, 'VariableName'); 34 | } 35 | _ws.limitBefore(idStartToken, 'VariableName'); 36 | 37 | if (declarator.init) { 38 | _ws.limitAfter(declarator.id.endToken, 'VariableName'); 39 | var equalSign = _tk.findNext(declarator.id.endToken, '='); 40 | var valueStart = _tk.findNextNonEmpty(equalSign); 41 | _br.limitBefore(valueStart, 'VariableValue'); 42 | _ws.limitBefore(valueStart, 'VariableValue'); 43 | _br.limitAfter(declarator.endToken, 'VariableValue'); 44 | _ws.limitAfter(declarator.endToken, 'VariableValue'); 45 | } 46 | }); 47 | 48 | // always add a space after the "var" keyword 49 | _ws.limitAfter(node.startToken, 1); 50 | 51 | if (_tk.isSemiColon(node.endToken)) { 52 | _br.limit(node.endToken, 'VariableDeclarationSemiColon'); 53 | _ws.limit(node.endToken, 'VariableDeclarationSemiColon'); 54 | } 55 | }; 56 | 57 | 58 | exports.getIndentEdges = function(node, opts) { 59 | var edges = []; 60 | 61 | var isMulti = node.declarations.length > 1; 62 | 63 | if ((opts.MultipleVariableDeclaration && isMulti) || 64 | (opts.SingleVariableDeclaration && !isMulti) 65 | ) { 66 | edges.push(node); 67 | } 68 | 69 | node.declarations.forEach(function(declaration) { 70 | var init = declaration.init; 71 | if (helpers.shouldIndentChild(node, init, opts)) { 72 | var end = init.endToken.value === ')' ? 73 | _tk.findPrevNonEmpty(init.endToken) : 74 | init.endToken.next; 75 | edges.push({ 76 | level: opts['VariableDeclaration.' + init.type], 77 | startToken: init.startToken, 78 | endToken: end 79 | }); 80 | } 81 | }); 82 | 83 | return edges; 84 | }; 85 | -------------------------------------------------------------------------------- /lib/hooks/expressionParentheses.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _tk = require('rocambole-token'); 4 | var _ws = require('rocambole-whitespace'); 5 | var debug = require('debug')('esformatter:parentheses'); 6 | 7 | 8 | exports.addSpaceInside = addSpaceInsideExpressionParentheses; 9 | function addSpaceInsideExpressionParentheses(node) { 10 | var parentheses = getParentheses(node); 11 | if (parentheses) { 12 | _ws.limitAfter(parentheses.opening, 'ExpressionOpeningParentheses'); 13 | _ws.limitBefore(parentheses.closing, 'ExpressionClosingParentheses'); 14 | } 15 | } 16 | 17 | 18 | exports.getParentheses = getParentheses; 19 | function getParentheses(node) { 20 | if (!isValidExpression(node)) { 21 | debug('not valid expression: %s', node.type); 22 | return; 23 | } 24 | 25 | var opening = node.startToken; 26 | if (/^(?:Binary|Logical)Expression$/.test(node.type) || opening.value !== '(') { 27 | opening = _tk.findPrevNonEmpty(opening); 28 | } 29 | 30 | if (!opening || opening.value !== '(') { 31 | // "safe" to assume it is not inside parentheses 32 | debug( 33 | 'opening is not a parentheses; type: %s, opening: "%s"', 34 | node.type, 35 | opening && opening.value 36 | ); 37 | return; 38 | } 39 | 40 | var token = opening; 41 | var count = 0; 42 | var closing; 43 | 44 | while (token) { 45 | if (token.value === '(') { 46 | count += 1; 47 | } else if (token.value === ')') { 48 | count -= 1; 49 | } 50 | if (count === 0) { 51 | closing = token; 52 | break; 53 | } 54 | token = token.next; 55 | } 56 | 57 | if (!closing) { 58 | debug('not inside parentheses', count); 59 | return; 60 | } 61 | 62 | debug( 63 | 'found parentheses; type: %s, opening: "%s", closing: "%s"', 64 | node.type, 65 | opening && opening.value, 66 | closing && closing.value 67 | ); 68 | 69 | return { 70 | opening: opening, 71 | closing: closing 72 | }; 73 | } 74 | 75 | // Literal when inside BinaryExpression might be surrounded by parenthesis 76 | // CallExpression and ArrayExpression don't need spaces 77 | var needExpressionParenthesesSpaces = { 78 | Literal: true, 79 | CallExpression: false, 80 | FunctionExpression: false, 81 | ArrayExpression: false, 82 | ObjectExpression: false, 83 | // Special is used when we need to override default behavior 84 | Special: true 85 | }; 86 | 87 | 88 | function isValidExpression(node) { 89 | var needSpaces = needExpressionParenthesesSpaces[node.type]; 90 | 91 | if (needSpaces) { 92 | return true; 93 | } 94 | 95 | if (needSpaces == null && node.type.indexOf('Expression') !== -1) { 96 | if (node.type === 'ExpressionStatement' && 97 | (node.expression.callee && node.expression.callee.type === 'FunctionExpression')) { 98 | // bypass IIFE 99 | return false; 100 | } 101 | return true; 102 | } 103 | 104 | return false; 105 | } 106 | 107 | -------------------------------------------------------------------------------- /test/compare/default/obj_expression-in.js: -------------------------------------------------------------------------------- 1 | foo.bar.Baz( { 2 | method2: function () {}, prop : 'dolor amet' 3 | , prop2 : 123 4 | }); 5 | 6 | // issue #142 7 | var foo = [{ 8 | bar: 42 9 | }]; 10 | 11 | function foo(a){ amet(123, a, {flag:true}); } 12 | ipsum({flag:true}); 13 | ipsum({flag:true,other:false}); 14 | ipsum({flag:true,other:false},789,'bar'); 15 | 16 | 17 | var obj = {foo:"bar", 'lorem' : 123, 18 | dolor :new Date() 19 | , "re": /\w+/g} ; 20 | 21 | // ObjectEpression within CallExpression needs to indent comments 22 | declare({ 23 | // comment 24 | create: {} 25 | }); 26 | 27 | this.element 28 | .add() 29 | .set({ 30 | // line comment 31 | // one more 32 | prop: "value" 33 | }); 34 | 35 | define( name, { 36 | _create: function() { 37 | this.element 38 | .add() 39 | .set({ 40 | // line comment 41 | // one more 42 | prop: "value" 43 | }); 44 | } 45 | }); 46 | 47 | x = { 48 | props: { 49 | // comment 50 | x: 1 51 | } 52 | }; 53 | 54 | var x = { 55 | data: x ? 56 | x() : 57 | // comment 58 | function() {} 59 | }; 60 | 61 | // edge case 62 | for (key in { 63 | foo:'bar', 64 | lorem:'ipsum' 65 | }) { 66 | doStuff(key); 67 | } 68 | 69 | // issues #47 and #166 70 | Ext.define('VMS.model.User', { 71 | extend: 'Ext.data.Model', 72 | idProperty: 'UserID', 73 | fields: [ 74 | { 75 | // foo 76 | name: 'UserID', 77 | type: 'int' // bar 78 | }, 79 | // dolor 80 | // amet 81 | { 82 | name: 'FirstName', 83 | type: 'string' 84 | }, 85 | { 86 | name: 'LastName', 87 | type: 'string' 88 | // align with previous line because of line break 89 | 90 | // align with "}" 91 | // dolor sit amet 92 | // maecennas ullamcor 93 | } 94 | ] 95 | }); 96 | 97 | 98 | // issue #175 99 | var ItemsSchema = new Schema({ 100 | name: String // comments 101 | ,dds: "" 102 | }); 103 | 104 | 105 | this 106 | .foo({ 107 | bar: 'baz' 108 | }); 109 | 110 | 111 | // issue #193 112 | foo = function() { 113 | var a, 114 | b, 115 | c; 116 | var bar = this.baz({}); 117 | }; 118 | 119 | // issue #226 120 | var o = { 121 | a: 0, 122 | get b(){}, 123 | set c (x){}, 124 | method1(foo) {}, 125 | method2 ( bar ) 126 | {} 127 | }; 128 | 129 | o = { 130 | get b(){return 'test'; }, 131 | set c(x){} 132 | }; 133 | 134 | x = { 135 | at: "left" + 136 | "top" 137 | }; 138 | x = { 139 | at: a && 140 | b 141 | }; 142 | 143 | // ES6 Object Literal Property Value Shorthand 144 | x = { w, y, z } 145 | 146 | // issue #295 147 | o = { 148 | foo: ( 149 | lorem && 150 | ipsum 151 | ), 152 | bar: ( 153 | dolor || 154 | amet 155 | ) 156 | }; 157 | 158 | // issue #306 159 | unary = { 160 | a: !!(dolor || 161 | amet && ipsum 162 | ) 163 | }; 164 | 165 | // issue ##287 166 | var i = 0; 167 | var obj = { 168 | ["foo" + ++i]: i, 169 | [ "foo" + ++i ] : i, 170 | ["foo" + ++i] 171 | : 172 | 1 173 | }; 174 | -------------------------------------------------------------------------------- /test/api.spec.js: -------------------------------------------------------------------------------- 1 | //jshint node:true 2 | /*global describe, it*/ 3 | "use strict"; 4 | 5 | var expect = require('chai').expect; 6 | var esformatter = require('../lib/esformatter'); 7 | 8 | 9 | describe('API', function() { 10 | 11 | describe('exposed API', function() { 12 | // plugins might need to access some internal methods from esformatter 13 | // so we check if these methods are really available 14 | var limit = require('../lib/limit'); 15 | var options = require('../lib/options'); 16 | 17 | it('shoud expose useful methods to plugin authors', function() { 18 | // we don't need to check implementation here since these methods are 19 | // used internally 20 | expect(limit.before).to.be.a('function'); 21 | expect(limit.after).to.be.a('function'); 22 | expect(limit.around).to.be.a('function'); 23 | expect(options.set).to.be.a('function'); 24 | expect(options.get).to.be.a('function'); 25 | expect(options.getRc).to.be.a('function'); 26 | expect(options.loadAndParseConfig).to.be.a('function'); 27 | expect(esformatter.rc).to.be.a('function'); 28 | }); 29 | }); 30 | 31 | describe('esformatter.rc', function() { 32 | // PS: CLI is already testing this method indirectly, we are only checking 33 | // for edge cases for now 34 | 35 | it('should return custom options if root == true', function() { 36 | expect( 37 | esformatter.rc(null, {root:true}) 38 | ).to.be.eql({root:true}); 39 | }); 40 | 41 | it('should return custom options if preset', function() { 42 | expect( 43 | esformatter.rc(null, {preset:'default'}) 44 | ).to.be.eql({preset:'default'}); 45 | }); 46 | 47 | it('should merge the custom option', function() { 48 | var customOpts = { 49 | whiteSpace: { 50 | before: { 51 | "ArrayExpressionClosing" : 1 52 | }, 53 | after: { 54 | "ArrayExpressionOpening" : 1 55 | } 56 | } 57 | }; 58 | var result = esformatter.rc('test/compare/rc/top-in.js', customOpts); 59 | expect(result.whiteSpace.before.FunctionDeclarationOpeningBrace).to.be.eql(0); 60 | expect(result.whiteSpace.before.ArrayExpressionClosing).to.be.eql(1); 61 | expect(result.whiteSpace.after.ArrayExpressionOpening).to.be.eql(1); 62 | }); 63 | 64 | it('should merge rcs from parent folder', function() { 65 | var result = esformatter.rc('test/compare/rc/nested/nested-in.js'); 66 | expect(result.indent.value).to.be.eql('\t'); 67 | expect(result.whiteSpace.before.FunctionDeclarationOpeningBrace).to.be.eql(0); 68 | }); 69 | 70 | it('should merge .esformatter and package.json files', function() { 71 | var result = esformatter.rc('test/compare/rc/package/nested/pkg_nested-in.js'); 72 | expect(result.indent.value).to.be.eql('\t'); 73 | expect(result.lineBreak.before.FunctionDeclarationOpeningBrace).to.be.eql(1); 74 | expect(result.lineBreak.before.FunctionDeclarationClosingBrace).to.be.eql(0); 75 | }); 76 | }); 77 | }); 78 | --------------------------------------------------------------------------------