├── test ├── compare │ ├── default │ │ ├── empty_file-in.js │ │ ├── empty_file-out.js │ │ ├── inplace-out.js │ │ ├── inplace-in.js │ │ ├── array_pattern-out.js │ │ ├── array_pattern-in.js │ │ ├── throw_statement-in.js │ │ ├── object_pattern-out.js │ │ ├── throw_statement-out.js │ │ ├── block_statement-in.js │ │ ├── jsx-in.js │ │ ├── jsx-out.js │ │ ├── object_pattern-in.js │ │ ├── block_statement-out.js │ │ ├── comma_operator-in.js │ │ ├── README.md │ │ ├── comma_operator-out.js │ │ ├── do_while_statement-in.js │ │ ├── member_expression-out.js │ │ ├── new_expression-out.js │ │ ├── new_expression-in.js │ │ ├── member_expression-in.js │ │ ├── iife-in.js │ │ ├── do_while_statement-out.js │ │ ├── flow-in.js │ │ ├── flow-out.js │ │ ├── iife-out.js │ │ ├── while_statement-out.js │ │ ├── binary_expression-in.js │ │ ├── binary_expression-out.js │ │ ├── while_statement-in.js │ │ ├── for_statement-in.js │ │ ├── unary_expression-in.js │ │ ├── unary_expression-out.js │ │ ├── for_statement-out.js │ │ ├── logical_expression-in.js │ │ ├── logical_expression-out.js │ │ ├── for_of_statement-out.js │ │ ├── for_in_statement-out.js │ │ ├── for_of_statement-in.js │ │ ├── for_in_statement-in.js │ │ ├── arrow_function_expression-out.js │ │ ├── conditional_expression-in.js │ │ ├── conditional_expression-out.js │ │ ├── array_expression-in.js │ │ ├── array_expression-out.js │ │ ├── arrow_function_expression-in.js │ │ ├── comments-out.js │ │ ├── class_declaration-in.js │ │ ├── class_declaration-out.js │ │ ├── class_expression-in.js │ │ ├── class_expression-out.js │ │ ├── module-out.js │ │ ├── assignment_expression-in.js │ │ ├── assignment_expression-out.js │ │ ├── comments-in.js │ │ ├── module-in.js │ │ ├── switch_statement-out.js │ │ ├── switch_statement-in.js │ │ ├── function_expression-out.js │ │ ├── var-out.js │ │ ├── var-in.js │ │ ├── function_expression-in.js │ │ ├── try_statement-out.js │ │ └── try_statement-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 │ │ │ │ └── function.json │ │ │ ├── package-out.js │ │ │ ├── nested │ │ │ │ ├── .esformatter │ │ │ │ ├── pkg_nested-in.js │ │ │ │ ├── indent.json │ │ │ │ ├── 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 │ │ ├── variable_declaration-config.json │ │ ├── variable_declaration-out.js │ │ ├── comment_group-config.json │ │ ├── multi-indent-in.js │ │ ├── argumentlist-config.json │ │ ├── array_bug-config.json │ │ ├── object_pattern-2-out.js │ │ ├── negative_indent-config.json │ │ ├── new_expression-config.json │ │ ├── for_statement-config.json │ │ ├── iife-in.js │ │ ├── arrow_function_expression-out.js │ │ ├── arrow_function_expression-in.js │ │ ├── conditional_expression-out.js │ │ ├── conditional_expression-in.js │ │ ├── align_comments-config.json │ │ ├── iife-out.js │ │ ├── member_expression-config.json │ │ ├── object_pattern-2-in.js │ │ ├── arrow_function_expression-config.json │ │ ├── class-in.js │ │ ├── expression_parentheses-config.json │ │ ├── class-out.js │ │ ├── multi-indent-out.js │ │ ├── unary_expression-config.json │ │ ├── iife-config.json │ │ ├── negative_indent-in.js │ │ ├── function_expression_bug-config.json │ │ ├── argumentlist-out.js │ │ ├── class_declaration-config.json │ │ ├── negative_indent-out.js │ │ ├── object_expression-2-config.json │ │ ├── if_statement_spacy-config.json │ │ ├── argumentlist-in.js │ │ ├── README.md │ │ ├── for_in_statement-config.json │ │ ├── for_of_statement-config.json │ │ ├── new_expression-in.js │ │ ├── basic_function_indent_2-config.json │ │ ├── new_expression-out.js │ │ ├── object_pattern-config.json │ │ ├── object_expression-3-in.js │ │ ├── align_comments-in.js │ │ ├── align_comments-out.js │ │ ├── array_expression-in.js │ │ ├── object_expression-3-out.js │ │ ├── array_expression-out.js │ │ ├── conditional_expression-config.json │ │ ├── object_pattern-2-config.json │ │ ├── class-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 │ │ ├── unary_expression-in.js │ │ ├── array_expression-2-config.json │ │ ├── unary_expression-out.js │ │ ├── top-level-indent-exception-out.js │ │ ├── array_expression-config.json │ │ ├── object_expression-in.js │ │ ├── module-config.json │ │ ├── switch_statement-in.js │ │ ├── if_statement-config.json │ │ ├── top-level-indent-exception-in.js │ │ ├── expression_parentheses-in.js │ │ ├── basic_function_indent-config.json │ │ ├── expression_parentheses-out.js │ │ ├── object_expression-out.js │ │ ├── if_statement-in.js │ │ ├── if_statement-out.js │ │ ├── array_expression-2-out.js │ │ ├── class_declaration-in.js │ │ ├── class_declaration-out.js │ │ ├── try_statement-config.json │ │ ├── module-in.js │ │ ├── module-out.js │ │ ├── try_statement-in.js │ │ └── try_statement-out.js │ ├── fake-preset │ │ ├── 2-in.js │ │ ├── 2-out.js │ │ └── package.json │ ├── .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 │ └── esformatter-test-plugin.js ├── preset │ ├── fake1 │ │ ├── esformatter-preset-fake-1.js │ │ └── package.json │ └── fake2 │ │ ├── esformatter-preset-fake-2.js │ │ └── package.json ├── transform.spec.js ├── runner.js ├── pipe.spec.js └── helpers.js ├── lib ├── hooks │ ├── ExportSpecifier.js │ ├── ThrowStatement.js │ ├── ExportDefaultDeclaration.js │ ├── UpdateExpression.js │ ├── SequenceExpression.js │ ├── ExportAllDeclaration.js │ ├── ObjectPattern.js │ ├── BinaryExpression.js │ ├── ArrayPattern.js │ ├── ExportNamedDeclaration.js │ ├── BlockStatement.js │ ├── SwitchStatement.js │ ├── ClassDeclarationAndExpression.js │ ├── CatchClause.js │ ├── DoWhileStatement.js │ ├── LogicalExpression.js │ ├── ImportDeclaration.js │ ├── AssignmentExpression.js │ ├── MethodDefinition.js │ ├── FunctionDeclaration.js │ ├── MemberExpression.js │ ├── ConditionalExpression.js │ ├── TryStatement.js │ ├── WhileStatement.js │ ├── UnaryExpression.js │ ├── ForStatement.js │ ├── ForInStatement.js │ ├── ForOfStatement.js │ ├── ImportSpecifier.js │ ├── SwitchCase.js │ ├── ArrayExpression.js │ ├── ArrowFunctionExpression.js │ ├── ReturnStatement.js │ ├── Params.js │ └── FunctionExpression.js ├── helpers.js ├── preset │ ├── default.js │ ├── default-indent.js │ └── jquery.js ├── limit.js ├── esformatter.js ├── diff.js └── format.js ├── .gitignore ├── .travis.yml ├── doc ├── cli.txt └── presets.md ├── .editorconfig ├── LICENSE.md └── bin └── esformatter /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/custom/basic_function_indent-in.js: -------------------------------------------------------------------------------- 1 | function foo(x,y){return x+y;} 2 | -------------------------------------------------------------------------------- /test/compare/rc/package/rc/nested-in.js: -------------------------------------------------------------------------------- 1 | function foo() { 2 | lorem(); 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/rc/package/rc/nested-out.js: -------------------------------------------------------------------------------- 1 | function foo () { 2 | lorem(); 3 | } 4 | -------------------------------------------------------------------------------- /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/custom/basic_function_indent_2-out.js: -------------------------------------------------------------------------------- 1 | function foo(x, y) 2 | { 3 | return x + y; 4 | } 5 | -------------------------------------------------------------------------------- /test/compare/default/inplace-in.js: -------------------------------------------------------------------------------- 1 | var a = 2 | 3 | 40 4 | 5 | ; 6 | 7 | -------------------------------------------------------------------------------- /test/compare/rc/package/nested/.esformatter: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "./indent.json" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /test/compare/fake-preset/2-in.js: -------------------------------------------------------------------------------- 1 | function foo() { 2 | return [ 3 | true, 4 | false 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/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/fake-preset/2-out.js: -------------------------------------------------------------------------------- 1 | function foo() { 2 | return [ 3 | false, 4 | false 5 | ]; 6 | } 7 | -------------------------------------------------------------------------------- /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/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/rc/package/nested/indent.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../rc/function.json", 3 | "indent": { 4 | "value": "\t" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /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/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/default/array_pattern-out.js: -------------------------------------------------------------------------------- 1 | var [lorem, ipsum] = arr; 2 | 3 | var [x, y, z] = position; 4 | 5 | // #444 6 | var [a,, b] = [1, 2, 3]; 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/default/array_pattern-in.js: -------------------------------------------------------------------------------- 1 | var [ lorem , ipsum ] = arr; 2 | 3 | var [ 4 | x, 5 | y, 6 | z 7 | ] = position; 8 | 9 | // #444 10 | var [a , , b] = [1,2,3]; 11 | -------------------------------------------------------------------------------- /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/rc/.esformatter: -------------------------------------------------------------------------------- 1 | { 2 | "indent": { 3 | "value": " " 4 | }, 5 | "whiteSpace": { 6 | "before": { 7 | "FunctionDeclarationOpeningBrace" : 0 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/compare/rc/package/rc/.esformatter: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": [ 4 | "./function.json" 5 | ], 6 | "indent": { 7 | "value": "\t", 8 | "FunctionDeclaration": 4 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/object_pattern-2-out.js: -------------------------------------------------------------------------------- 1 | // #441 2 | var {foo, bar, ipsum} = object; 3 | 4 | var { 5 | foo, 6 | bar, 7 | ipsum 8 | } = object; 9 | 10 | var { 11 | foo, 12 | bar, 13 | ipsum 14 | } = object; 15 | -------------------------------------------------------------------------------- /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/rc/package/rc/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "indent": { 3 | "value": " ", 4 | "FunctionDeclaration": 2 5 | }, 6 | "whiteSpace": { 7 | "after": { 8 | "FunctionName": 1 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /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/new_expression-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "whiteSpace": { 3 | "before": { 4 | "CalleeClosingParentheses": "1" 5 | }, 6 | "after": { 7 | "CalleeOpeningParentheses": "1" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/compare/fake-preset/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "testing extends inside package.json", 4 | "esformatter": { 5 | "root": true, 6 | "extends": [ 7 | "preset:fake-2" 8 | ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /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/custom/arrow_function_expression-out.js: -------------------------------------------------------------------------------- 1 | // issue #400 2 | () => process.exit( 0 ); 3 | ( example ) => process.exit( 0 ); 4 | ( example ) => { 5 | process.exit( 0 ); 6 | }; 7 | function example() { 8 | return process.exit( 0 ); 9 | } 10 | -------------------------------------------------------------------------------- /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/arrow_function_expression-in.js: -------------------------------------------------------------------------------- 1 | // issue #400 2 | ( ) => process.exit(0 ); 3 | ( example ) => process.exit( 0); 4 | (example) => { 5 | process.exit( 0 ); 6 | }; 7 | function example() { 8 | return process.exit( 0 ); 9 | } 10 | -------------------------------------------------------------------------------- /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/object_pattern-2-in.js: -------------------------------------------------------------------------------- 1 | // #441 2 | var {foo,bar,ipsum} = object; 3 | 4 | var { 5 | foo, 6 | bar, 7 | ipsum 8 | } = object; 9 | 10 | var { 11 | 12 | foo, 13 | 14 | bar, 15 | 16 | ipsum 17 | 18 | 19 | 20 | } 21 | 22 | = object; 23 | -------------------------------------------------------------------------------- /test/compare/custom/arrow_function_expression-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "whiteSpace": { 3 | "before": { 4 | "ArgumentList": 1, 5 | "ParameterList": 1 6 | }, 7 | "after": { 8 | "ArgumentList": 1, 9 | "ParameterList": 1 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /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 | // issue #423 10 | class Foo 11 | extends Bar { 12 | fn() {} 13 | } 14 | 15 | -------------------------------------------------------------------------------- /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/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 | // issue #423 12 | class Foo 13 | extends Bar { 14 | fn () {} 15 | } 16 | 17 | -------------------------------------------------------------------------------- /test/compare/default/block_statement-in.js: -------------------------------------------------------------------------------- 1 | { 2 | var foo = 123; 3 | bar(foo) 4 | } 5 | 6 | function dolor() { { let amet = 'maecennas'; 7 | console.log(amet) } } 8 | 9 | // #430 10 | function a() { var arr2 = [] } 11 | var x = 1 12 | { 13 | var x = 2 14 | console.log(x) } 15 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/unary_expression-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "whiteSpace": { 3 | "before": { 4 | "UnaryExpressionOperator": 1, 5 | "UpdateExpressionOperator": 1 6 | }, 7 | "after": { 8 | "UnaryExpressionOperator": 1, 9 | "UpdateExpressionOperator": 1 10 | 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /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": "esformatter-test-plugin.js", 7 | "author": "Miller Medeiros", 8 | "license": "ISC" 9 | } 10 | -------------------------------------------------------------------------------- /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/default/block_statement-out.js: -------------------------------------------------------------------------------- 1 | { 2 | var foo = 123; 3 | bar(foo) 4 | } 5 | 6 | function dolor() { 7 | { 8 | let amet = 'maecennas'; 9 | console.log(amet) 10 | } 11 | } 12 | 13 | // #430 14 | function a() { 15 | var arr2 = [] 16 | } 17 | var x = 1 18 | { 19 | var x = 2 20 | console.log(x) 21 | } 22 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/preset/fake1/esformatter-preset-fake-1.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // IMPORTANT: run `npm rm esformatter-preset-fake-1 && npm i test/preset/fake1` 4 | // every time you update this file! 5 | 6 | module.exports = { 7 | plugins: [ 8 | require('esformatter-test-plugin') 9 | ], 10 | indent: { 11 | FunctionExpression: 42 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /test/preset/fake2/esformatter-preset-fake-2.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // IMPORTANT: run `npm rm esformatter-preset-fake-2 && npm i test/preset/fake2` 4 | // every time you update this file! 5 | 6 | module.exports = { 7 | extends: [ 8 | require('esformatter-preset-fake-1') 9 | ], 10 | indent: { 11 | FunctionDeclaration: 2 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /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/class_declaration-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lineBreak": { 3 | "before": { 4 | "MethodDefinition": 3, 5 | "MethodDefinitionOpeningBrace": 1 6 | }, 7 | "after": { 8 | "MethodDefinitionClosingBrace": 3 9 | } 10 | }, 11 | "whiteSpace": { 12 | "after": { 13 | "MethodDefinitionName": 1 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8" 4 | - "10" 5 | - "12" 6 | script: 7 | - "npm test --coverage" 8 | - "npm run-script lint" 9 | branches: 10 | only: 11 | - master 12 | notifications: 13 | irc: 14 | channels: 15 | - "irc.freenode.org#esformatter" 16 | on_success: change 17 | use_notice: true 18 | skip_join: true 19 | -------------------------------------------------------------------------------- /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/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/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/preset/fake2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "esformatter-preset-fake-2", 4 | "version": "1.0.0", 5 | "description": "test if esformatter is able to load locally installed presets", 6 | "main": "esformatter-preset-fake-2.js", 7 | "author": "Miller Medeiros", 8 | "license": "MIT", 9 | "dependencies": { 10 | "esformatter-preset-fake-1": "file:../fake1" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/preset/fake1/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "esformatter-preset-fake-1", 4 | "version": "1.0.0", 5 | "description": "test if esformatter is able to load locally installed presets", 6 | "main": "esformatter-preset-fake-1.js", 7 | "author": "Miller Medeiros", 8 | "license": "MIT", 9 | "dependencies": { 10 | "esformatter-test-plugin": "file:../../plugin" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/compare/custom/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 | 15 | // #434 16 | context = new (window.AudioContext || window.webkitAudioContext)(); 17 | new ( a.b ); 18 | (foo || bar)(); 19 | -------------------------------------------------------------------------------- /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/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 | 14 | // #434 15 | context = new ( window.AudioContext || window.webkitAudioContext )(); 16 | new ( a.b ); 17 | ( foo || bar )(); 18 | -------------------------------------------------------------------------------- /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/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 | c, 21 | someMethod () { 22 | bar() 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lib/hooks/UpdateExpression.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _limit = require('../limit'); 4 | 5 | exports.format = function UpdateExpression(node) { 6 | // we only really care about spaces between the operator and the argument 7 | if (node.startToken.value === node.operator) { 8 | _limit.after(node.startToken, 'UpdateExpressionOperator'); 9 | } else { 10 | _limit.before(node.endToken, 'UpdateExpressionOperator'); 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | c, 21 | someMethod () { 22 | bar() 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /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/default/do_while_statement-in.js: -------------------------------------------------------------------------------- 1 | do{console.log(i++)}while(i<100); do{i--}while(i); 2 | 3 | do{ 4 | console.log(i++) 5 | }while(i<100) 6 | do{i--}while(i); 7 | 8 | do n--; while(n&&foo()); 9 | 10 | do n--; while(n&&foo());do++i;while(amet(i)); 11 | 12 | // issue #256 13 | function main() { 14 | do if (true) return 1; while (true); 15 | } 16 | 17 | function main() { 18 | do 19 | if (true) return 1; 20 | while (true); 21 | } 22 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 the right of a BinaryExpression, LogicalExpression or 7 | // UnaryExpression 8 | if (!child || !opts[parent.type + '.' + child.type]) { 9 | return false; 10 | } 11 | 12 | return !child.right || !opts[child.right.type]; 13 | } 14 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/compare/custom/object_pattern-2-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lineBreak": { 3 | "before": { 4 | "ObjectPatternClosingBrace": "<2" 5 | }, 6 | "after": { 7 | "ObjectPatternClosingBrace": 0, 8 | "ObjectPatternComma": "<2", 9 | "ObjectPatternOpeningBrace": "<2" 10 | } 11 | }, 12 | "whiteSpace": { 13 | "before": { 14 | "ObjectPatternComma": 0 15 | }, 16 | "after": { 17 | "ObjectPatternComma": 1 18 | } 19 | } 20 | } 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/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 | 14 | // #434 15 | context = new (window.AudioContext || window.webkitAudioContext)(); 16 | (foo || bar)(); 17 | 18 | // #439 19 | var foo = new // ARRAY_COPY( 20 | Date(); 21 | 22 | console.log(foo); 23 | -------------------------------------------------------------------------------- /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 | "lineBreak": { 21 | "before": { 22 | "ClassExtendsKeyword": -1 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /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 | 15 | // #434 16 | context = new ( window.AudioContext || window.webkitAudioContext )(); 17 | ( foo || bar )(); 18 | 19 | // #439 20 | var foo = new // ARRAY_COPY( 21 | Date(); 22 | 23 | console.log(foo); 24 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 { 9 | console.log(i++) 10 | } while (i < 100) 11 | do { 12 | i-- 13 | } while (i); 14 | 15 | do n--; while (n && foo()); 16 | 17 | do n--; while (n && foo()); 18 | do ++i; while (amet(i)); 19 | 20 | // issue #256 21 | function main() { 22 | do 23 | if (true) return 1; 24 | while (true); 25 | } 26 | 27 | function main() { 28 | do 29 | if (true) return 1; 30 | while (true); 31 | } 32 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /test/plugin/esformatter-test-plugin.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 | -------------------------------------------------------------------------------- /lib/preset/default.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | "extends": [ 5 | require('./default-indent'), 6 | require('./default-linebreak-before'), 7 | require('./default-linebreak-after'), 8 | require('./default-whitespace-before'), 9 | require('./default-whitespace-after') 10 | ], 11 | 12 | "esformatter": { 13 | "allowShebang": true 14 | }, 15 | 16 | "indent": { 17 | "value": " ", 18 | "alignComments": true, 19 | }, 20 | 21 | "lineBreak": { 22 | "value": "\n" 23 | }, 24 | 25 | "whiteSpace": { 26 | "value": " ", 27 | "removeTrailing": 1 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /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/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 | "MethodName": 1, 22 | "ObjectExpressionOpeningBrace": 1, 23 | "PropertyValue": -1 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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/custom/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-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 | -------------------------------------------------------------------------------- /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 | // array pattern might be like `[a,,b]`, so second element is actually `null` 11 | // that's why we can't blindly use the el.endToken so we store `searchStart` 12 | var searchStart = node.startToken; 13 | node.elements.forEach(function(el) { 14 | searchStart = tk.findNext( 15 | el ? el.endToken : searchStart, 16 | [',', ']'] 17 | ); 18 | if (searchStart.value === ',') { 19 | limit.around(searchStart, 'ArrayPatternComma'); 20 | } 21 | }); 22 | }; 23 | -------------------------------------------------------------------------------- /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/custom/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/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/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 | 47 | // issue #421 48 | let foo = foo || 49 | 42; 50 | 51 | let bar = bar() || 52 | 42; -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | var ImportDeclaration = require('./ImportDeclaration'); 8 | 9 | exports.format = function ExportNamedDeclaration(node) { 10 | _br.limitAfter(node.startToken, 0); 11 | _ws.limitAfter(node.startToken, 1); 12 | 13 | // node.specifiers is actually handled by the ExportSpecifier hook! 14 | 15 | if (!node.specifiers.length) return; 16 | 17 | var fromKeyword = _tk.findPrev(node.endToken, 'from'); 18 | if (fromKeyword) { 19 | // safeguard against `export { foo, bar };` (no "from") 20 | _br.limit(fromKeyword, 0); 21 | _ws.limit(fromKeyword, 1); 22 | } 23 | }; 24 | 25 | exports.getIndentEdges = ImportDeclaration.getIndentEdges; 26 | -------------------------------------------------------------------------------- /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 | 48 | // issue #421 49 | let foo = foo || 50 | 42; 51 | 52 | let bar = bar() || 53 | 42; -------------------------------------------------------------------------------- /lib/hooks/BlockStatement.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _limit = require('../limit'); 4 | 5 | exports.format = function BlockStatement(node) { 6 | if (!shouldHandle(node)) { 7 | return; 8 | } 9 | 10 | _limit.around(node.startToken, 'BlockStatementOpeningBrace'); 11 | _limit.around(node.endToken, 'BlockStatementClosingBrace'); 12 | }; 13 | 14 | function shouldHandle(node) { 15 | // BlockStatement is very generic and used in a bunch of different cases 16 | // (function/do/while/arrowFunction/for/forOf/...) so we only handle a few 17 | // cases here and let the other hooks take care of everything else 18 | return node.parent.type === 'Program' || 19 | node.parent.type === 'BlockStatement'; 20 | } 21 | 22 | exports.getIndentEdges = function(node) { 23 | if (!shouldHandle(node)) { 24 | return false; 25 | } 26 | return node; 27 | }; 28 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /test/compare/custom/module-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lineBreak": { 3 | "before": { 4 | // there is a conflict between the 5 | // lineBreak.after.FunctionDeclarationClosingBrace and the line break 6 | // around nodes logic, so we need to set "before" & "after" for all the 7 | // export/import declarations to override it 8 | "ExportAllDeclaration": 2, 9 | "ExportDefaultDeclaration": 2, 10 | "ExportNamedDeclaration": 2, 11 | "ModuleSpecifierClosingBrace": 1, 12 | "ModuleSpecifierComma": 0 13 | }, 14 | "after": { 15 | "ExportAllDeclaration": 2, 16 | "ExportDefaultDeclaration": 2, 17 | "ExportNamedDeclaration": 2, 18 | "ImportDeclaration": 2, 19 | "ModuleSpecifierOpeningBrace": 1, 20 | "ModuleSpecifierClosingBrace": -1, 21 | "ModuleSpecifierComma": 1 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /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/ClassDeclarationAndExpression.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // this file handles both ClassDeclaration and ClassExpression 4 | 5 | var br = require('rocambole-linebreak'); 6 | var tk = require('rocambole-token'); 7 | var ws = require('rocambole-whitespace'); 8 | var limit = require('../limit'); 9 | 10 | exports.format = function ClassDeclarationAndExpression(node) { 11 | var classKeyword = node.startToken; 12 | br.limit(classKeyword, 'ClassKeyword'); 13 | ws.limitAfter(classKeyword, 1); 14 | 15 | var opening = node.body.startToken; 16 | var extendsKeyword = tk.findInBetween(classKeyword, opening, 'extends'); 17 | if (extendsKeyword) { 18 | br.limit(extendsKeyword, 'ClassExtendsKeyword'); 19 | ws.limit(extendsKeyword, 1); 20 | } 21 | 22 | limit.around(opening, 'ClassOpeningBrace'); 23 | limit.around(node.body.endToken, 'ClassClosingBrace'); 24 | }; 25 | 26 | exports.getIndentEdges = function(node) { 27 | return node; 28 | }; 29 | -------------------------------------------------------------------------------- /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/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 | "ParameterComma" : 0, 19 | "ParameterList" : 1, 20 | "FunctionDeclarationOpeningBrace" : 0, 21 | "FunctionDeclarationClosingBrace" : 1 22 | }, 23 | "after" : { 24 | "FunctionName" : 1, 25 | "ParameterComma" : 0, 26 | "ParameterList" : 1, 27 | "FunctionDeclarationOpeningBrace" : 1 28 | } 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | var edges = [ 22 | { // do 23 | startToken: node.startToken.next, 24 | endToken: node.body.endToken 25 | }, 26 | { // while 27 | startToken: _tk.findNext(node.body.endToken, '('), 28 | endToken: node.endToken.value === ')' ? node.endToken : _tk.findPrev(node.endToken, ')') 29 | } 30 | ]; 31 | 32 | return edges; 33 | }; 34 | -------------------------------------------------------------------------------- /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/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/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 | // another trap! 29 | if (asi && noBraces) 30 | dolor() 31 | else 32 | { amet();} 33 | 34 | 35 | 36 | // issue #34 (break line comment into individual line) 37 | if ( window.DOMParser ) { // Standard 38 | tmp = new DOMParser(); 39 | xml = tmp.parseFromString( data , "text/xml" ); 40 | } else { // IE 41 | xml = new ActiveXObject( "Microsoft.XMLDOM" ); 42 | xml.async = "false"; 43 | xml.loadXML( data ); 44 | } 45 | 46 | 47 | // issue #196 48 | if (a) 49 | a(); // run a 50 | else if (b) 51 | b(); // run b 52 | else { 53 | c(); // run c 54 | } 55 | -------------------------------------------------------------------------------- /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 | // noop (#487) 14 | const f1 = () => {}; 15 | const f2 = () => {}; 16 | const f3 = () => {}; 17 | 18 | // default params (#285) 19 | let defaultParams = (x, y = 1, z = 2) => { 20 | return x + y + z; 21 | } 22 | 23 | // issue #393 24 | a = () => { 25 | test(() => { 26 | return 1 27 | }) 28 | test(() => { 29 | return 1 30 | }) 31 | } 32 | 33 | // issue #357 34 | const object = x => ({ 35 | x 36 | }); 37 | 38 | const retObject = x => { 39 | return { 40 | x 41 | }; 42 | } 43 | 44 | const array = x => [ 45 | x 46 | ]; 47 | 48 | const callWithObject = x => f({ 49 | x 50 | }); 51 | 52 | // issue #399 53 | const helloWorld = () => ( 54 | 'Hello' + ' ' + 'World' 55 | ) 56 | 57 | // issue #400 58 | ; 59 | () => process.exit(0); 60 | (example) => process.exit(0); 61 | function example() { 62 | return process.exit(0); 63 | } 64 | -------------------------------------------------------------------------------- /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/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 | // another trap! 42 | if(asi && noBraces) 43 | dolor() 44 | else 45 | { 46 | amet(); 47 | } 48 | 49 | 50 | 51 | // issue #34 (break line comment into individual line) 52 | if(window.DOMParser) 53 | { // Standard 54 | tmp = new DOMParser(); 55 | xml = tmp.parseFromString(data, "text/xml"); 56 | } 57 | else 58 | { // IE 59 | xml = new ActiveXObject("Microsoft.XMLDOM"); 60 | xml.async = "false"; 61 | xml.loadXML(data); 62 | } 63 | 64 | 65 | // issue #196 66 | if(a) 67 | a(); // run a 68 | else if(b) 69 | b(); // run b 70 | else 71 | { 72 | c(); // run c 73 | } 74 | -------------------------------------------------------------------------------- /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 | 20 | exports.getIndentEdges = function(node) { 21 | // IMPORTANT: getIndentEdges logic is reused by ExportNamedDeclaration 22 | var braceStart; 23 | node.specifiers.some(function(spec) { 24 | var prev = _tk.findPrev(spec.startToken, _tk.isCode); 25 | if (prev.value === '{') { 26 | braceStart = prev; 27 | return true; 28 | } 29 | }); 30 | if (!braceStart) { 31 | return; 32 | } 33 | 34 | return { 35 | startToken: braceStart, 36 | endToken: _tk.findNext(node.specifiers[node.specifiers.length - 1].endToken, '}') 37 | }; 38 | }; 39 | -------------------------------------------------------------------------------- /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/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 | // noop (#487) 11 | const f1 = () => {}; 12 | const f2 = ( ) => { }; 13 | const f3 = ( ) => { 14 | 15 | }; 16 | 17 | // default params (#285) 18 | let defaultParams = (x, y = 1, z = 2 ) => { 19 | return x + y + z; 20 | } 21 | 22 | // issue #393 23 | a = () => { 24 | test( () => { 25 | return 1 26 | }) 27 | test(() => { 28 | return 1 29 | }) 30 | } 31 | 32 | // issue #357 33 | const object = x => ({ 34 | x 35 | }); 36 | 37 | const retObject = x => { 38 | return { 39 | x 40 | }; 41 | } 42 | 43 | const array = x => [ 44 | x 45 | ]; 46 | 47 | const callWithObject = x => f({ 48 | x 49 | }); 50 | 51 | // issue #399 52 | const helloWorld = () => ( 53 | 'Hello' + ' ' + 'World' 54 | ) 55 | 56 | // issue #400 57 | ; 58 | ( ) => process.exit( 0 ); 59 | ( example ) => process.exit( 0 ); 60 | function example() { 61 | return process.exit( 0 ); 62 | } 63 | -------------------------------------------------------------------------------- /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/custom/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 14 | 15 | constructor(properties) { 16 | this.properties = properties; 17 | } 18 | get prop() { 19 | return 'getter'; 20 | } 21 | set prop(val) { 22 | Foo.log('setting: ', val) 23 | } 24 | 25 | 26 | 27 | 28 | static log(msg, level = 'log') { 29 | console[level]('[Foo]', msg); 30 | } 31 | 32 | 33 | 34 | 35 | 36 | toObject() { 37 | return this.properties; 38 | } 39 | 40 | 41 | 42 | 43 | } 44 | 45 | // Multi line declaration 46 | class 47 | Foo 48 | extends 49 | Bar 50 | { 51 | } 52 | // The value to be extended can be produced by an arbitrary expression. 53 | class Foo extends BarNamespace.Bar{} 54 | class Foo extends BarNamespace['Bar'].Bar["Bar"]('bar').Bar("bar", "bar"){} 55 | class Foo extends(BarNamespace.bar)(){} 56 | -------------------------------------------------------------------------------- /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/hooks/MethodDefinition.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var br = require('rocambole-linebreak'); 4 | var limit = require('../limit'); 5 | var tk = require('rocambole-token'); 6 | var ws = require('rocambole-whitespace'); 7 | 8 | exports.format = function MethodDefinition(node) { 9 | br.limitAfter(node.startToken, 0); 10 | 11 | // key name 12 | if (node.startToken.value === '[') { 13 | // computed key 14 | limit.around(node.startToken, 'MethodDefinitionComputedOpening'); 15 | limit.around( 16 | tk.findNext(node.key.endToken, ']'), 17 | 'MethodDefinitionComputedClosing' 18 | ); 19 | } else { 20 | if (node.startToken !== node.key.startToken) { 21 | // limit to one space after get/set/static 22 | ws.limitAfter(node.startToken, 1); 23 | } 24 | ws.limitAfter(node.key.endToken, 'MethodDefinitionName'); 25 | } 26 | 27 | // curly braces {} 28 | var opening = node.value.body.startToken; 29 | limit.around(opening, 'MethodDefinitionOpeningBrace'); 30 | limit.around(node.endToken, 'MethodDefinitionClosingBrace'); 31 | var bodyFirstNonEmpty = tk.findNextNonEmpty(opening); 32 | if (bodyFirstNonEmpty.value === '}') { 33 | // noop 34 | limit.after(opening, 0); 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /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/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 | // babel-eslint reports async functions as generators. 14 | // 15 | // Make sure the generator function is not an async function before removing 16 | // the whitespace. 17 | // 18 | // This will prevent a function such as `async function fun() {}` being 19 | // converted to `asyncfunction fun() {}`. 20 | if (node.async) { 21 | _ws.limitAfter(node.startToken, 1); 22 | } else if (node.generator) { 23 | var genToken = _tk.findNextNonEmpty(node.startToken); 24 | _ws.limitBefore(genToken, 'FunctionGeneratorAsterisk'); 25 | } 26 | _params.format(node); 27 | _limit.around(node.body.startToken, 'FunctionDeclarationOpeningBrace'); 28 | _limit.around(node.body.endToken, 'FunctionDeclarationClosingBrace'); 29 | }; 30 | 31 | 32 | exports.getIndentEdges = function(node, opts) { 33 | return [ 34 | _params.getIndentEdges(node, opts), 35 | node.body 36 | ]; 37 | }; 38 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/api.spec.js'); 38 | m.addFile('test/plugins.spec.js'); 39 | // run slower tests later for faster feedback cyle 40 | // extremely helpful when running tests with `BAIL=true npm test` 41 | m.addFile('test/cli.spec.js'); 42 | m.addFile('test/pipe.spec.js'); 43 | 44 | m.run(function(err) { 45 | var exitCode = err ? 1 : 0; 46 | if (err) console.log('failed tests: ' + err); 47 | process.exit(exitCode); 48 | }); 49 | 50 | -------------------------------------------------------------------------------- /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 | 49 | // #470 50 | const mySym = Symbol('some-symbol'); 51 | class Foo { 52 | [ mySym ]() { 53 | return true; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /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/custom/class_declaration-out.js: -------------------------------------------------------------------------------- 1 | // #286 2 | class Foo extends Bar { 3 | 4 | 5 | constructor (properties, name = 'lorem', ...extra) 6 | { 7 | this.properties = properties; 8 | this.name = name; 9 | this.extra = extra; 10 | } 11 | 12 | 13 | static log (msg, level = 'log') 14 | { 15 | console[level](msg); 16 | } 17 | 18 | 19 | toObject () 20 | { 21 | return this.properties; 22 | } 23 | 24 | 25 | } 26 | class Foo extends Bar { 27 | // empty lines in between the MethodDefinition 28 | 29 | 30 | constructor (properties) 31 | { 32 | this.properties = properties; 33 | } 34 | 35 | 36 | get prop () 37 | { 38 | return 'getter'; 39 | } 40 | 41 | 42 | set prop (val) 43 | { 44 | Foo.log('setting: ', val) 45 | } 46 | 47 | 48 | static log (msg, level = 'log') 49 | { 50 | console[level]('[Foo]', msg); 51 | } 52 | 53 | 54 | toObject () 55 | { 56 | return this.properties; 57 | } 58 | 59 | 60 | } 61 | 62 | // Multi line declaration 63 | class Foo extends Bar { 64 | } 65 | // The value to be extended can be produced by an arbitrary expression. 66 | class Foo extends BarNamespace.Bar { 67 | } 68 | class Foo extends BarNamespace['Bar'].Bar["Bar"]('bar').Bar("bar", "bar") { 69 | } 70 | class Foo extends (BarNamespace.bar)() { 71 | } 72 | -------------------------------------------------------------------------------- /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 | 51 | // #470 52 | const mySym = Symbol('some-symbol'); 53 | class Foo { 54 | [mySym]() { 55 | return true; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 class { 36 | constructor(x, y) { 37 | this.x = x; 38 | this.y = y; 39 | } 40 | } 41 | 42 | // #408 43 | export { lorem, hipstersum, nosemicolon } 44 | 45 | export { FOO_CONST, myOtherFunc }; 46 | export { MY_CONST as THE_CONST, myFunc as theFunc }; 47 | 48 | export * from 'src/other_module'; 49 | export { foo, bar } from 'src/other_module'; 50 | export { foo as myFoo, baz } from 'src/other_module'; 51 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 default class { 43 | constructor(x, y) { 44 | this.x = x; 45 | this.y = y; 46 | } 47 | } 48 | 49 | export { FOO_CONST, myOtherFunc }; 50 | export { MY_CONST as THE_CONST, myFunc as theFunc }; 51 | 52 | export * from 'src/other_module'; 53 | export { foo , bar }from 'src/other_module'; 54 | export {foo as myFoo,baz} from 'src/other_module'; 55 | -------------------------------------------------------------------------------- /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 | bar 16 | = 123; 17 | 18 | // assignment operators 19 | 20 | x+= y 21 | x -= y 22 | x *= y 23 | x /= y 24 | x%= y 25 | x<<= y 26 | x >>= y 27 | x 28 | >>>= 29 | y 30 | x&= y 31 | x^=y 32 | x|=y 33 | 34 | 35 | // multiple same line 36 | this.a=b;this.c=d;this.e=f;this.g=h||0; 37 | 38 | function h(a,b,c,d,e){this._listener=b;this._isOnce=c;this.context=d;this._signal=a;this._priority=e||0} 39 | 40 | 41 | // test for issue #5 (related to parenthesis) 42 | doc=(context&&context.nodeType?context.ownerDocument||context:document); 43 | 44 | 45 | // issue #8 (multiple assignment + OR + indent) 46 | function iss8(){ 47 | if (proxy) { 48 | proxy.guid = fn.guid = fn.guid || jQuery.guid++; 49 | } 50 | } 51 | 52 | // issue #306: UnaryExpression 53 | hasNativeRequestAnimationFrame = !!( 54 | window.requestAnimationFrame || 55 | window.webkitRequestAnimationFrame || 56 | window.mozRequestAnimationFrame || 57 | window.msRequestAnimationFrame 58 | ); 59 | 60 | // issue #316 61 | export class Foobar extends EventEmitter { 62 | constructor(foo, bar, d = {}) { 63 | super(); 64 | var fooBar = { foo, bar }; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /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 | bar = 123; 13 | 14 | // assignment operators 15 | 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 | x |= y 27 | 28 | 29 | // multiple same line 30 | this.a = b; 31 | this.c = d; 32 | this.e = f; 33 | this.g = h || 0; 34 | 35 | function h(a, b, c, d, e) { 36 | this._listener = b; 37 | this._isOnce = c; 38 | this.context = d; 39 | this._signal = a; 40 | this._priority = e || 0 41 | } 42 | 43 | 44 | // test for issue #5 (related to parenthesis) 45 | doc = (context && context.nodeType ? context.ownerDocument || context : document); 46 | 47 | 48 | // issue #8 (multiple assignment + OR + indent) 49 | function iss8() { 50 | if (proxy) { 51 | proxy.guid = fn.guid = fn.guid || jQuery.guid++; 52 | } 53 | } 54 | 55 | // issue #306: UnaryExpression 56 | hasNativeRequestAnimationFrame = !!( 57 | window.requestAnimationFrame || 58 | window.webkitRequestAnimationFrame || 59 | window.mozRequestAnimationFrame || 60 | window.msRequestAnimationFrame 61 | ); 62 | 63 | // issue #316 64 | export class Foobar extends EventEmitter { 65 | constructor(foo, bar, d = {}) { 66 | super(); 67 | var fooBar = { 68 | foo, 69 | bar 70 | }; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | // multiple consecutive operators like `!!foo` should not have spaces in 25 | // between then (we consider whole block as a single operator) 26 | var operator = node.startToken; 27 | var prev = _tk.findPrev(operator, _tk.isNotEmpty); 28 | if (prev && prev.value === operator.value) { 29 | _ws.limitBefore(operator, 0); 30 | } else { 31 | _ws.limitBefore(operator, 'UnaryExpressionOperator'); 32 | } 33 | var next = _tk.findNext(operator, _tk.isNotEmpty); 34 | if (next && next.value === operator.value) { 35 | _ws.limitAfter(operator, 0); 36 | } else { 37 | _ws.limitAfter(operator, 'UnaryExpressionOperator'); 38 | } 39 | } 40 | }; 41 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 default class { 43 | constructor(x, y) { 44 | this.x = x; 45 | this.y = y; 46 | } 47 | } 48 | 49 | // #408 50 | export { lorem, hipstersum, nosemicolon } 51 | 52 | export { FOO_CONST, myOtherFunc }; 53 | export { MY_CONST as THE_CONST, myFunc as theFunc }; 54 | 55 | export * from 'src/other_module'; 56 | export { 57 | foo , 58 | bar 59 | }from 'src/other_module'; 60 | export {foo as myFoo,baz} from 'src/other_module'; 61 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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, { 5 | named1, 6 | named2 7 | } from 'src/mylib'; 8 | 9 | import theDefault from 'src/mylib'; 10 | 11 | import { 12 | named1, 13 | named2 14 | } from 'src/mylib'; 15 | 16 | // Renaming: import named1 as myNamed1 17 | import { 18 | named1 as myNamed1, 19 | named2 20 | } from 'src/mylib'; 21 | 22 | // Importing the module as an object 23 | // (with one property per named export) 24 | import * as mylib from 'src/mylib'; 25 | 26 | // Only load the module, don’t import anything 27 | import 'src/mylib'; 28 | 29 | export var myVar1 = 123; 30 | 31 | export let myVar2 = 'foo'; 32 | 33 | export const MY_CONST = 'BAR'; 34 | 35 | export function myFunc() { 36 | return 'myfunc'; 37 | } 38 | 39 | export function* myGeneratorFunc() { 40 | return yield someStuff(); 41 | } 42 | 43 | export class MyClass { 44 | constructor() { 45 | this.name = 'exports test'; 46 | } 47 | } 48 | 49 | export default class { 50 | constructor(x, y) { 51 | this.x = x; 52 | this.y = y; 53 | } 54 | } 55 | 56 | export { 57 | FOO_CONST, 58 | myOtherFunc 59 | }; 60 | 61 | export { 62 | MY_CONST as THE_CONST, 63 | myFunc as theFunc 64 | }; 65 | 66 | export * from 'src/other_module'; 67 | 68 | export { 69 | foo, 70 | bar 71 | } from 'src/other_module'; 72 | 73 | export { 74 | foo as myFoo, 75 | baz 76 | } from 'src/other_module'; 77 | 78 | -------------------------------------------------------------------------------- /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 | 74 | // Block inside Case (#432) 75 | var f = function(action, state) { 76 | switch (action.type) { 77 | case ADD_GROCERY: { 78 | var foo = 'bar' 79 | } 80 | default: 81 | return state 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | 75 | // Block inside Case (#432) 76 | var f = function (action, state) { 77 | switch (action.type) { 78 | case ADD_GROCERY: { 79 | var foo = 'bar' 80 | } 81 | default: 82 | return state 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lib/preset/default-indent.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | "indent": { 5 | "ArrayExpression": 1, 6 | "ArrayPattern": 1, 7 | "ArrowFunctionExpression": 1, 8 | "AssignmentExpression": 1, 9 | "AssignmentExpression.BinaryExpression": 1, 10 | "AssignmentExpression.LogicalExpression": 1, 11 | "AssignmentExpression.UnaryExpression": 1, 12 | "BlockStatement": 1, 13 | "CallExpression": 1, 14 | "CallExpression.BinaryExpression": 1, 15 | "CallExpression.LogicalExpression": 1, 16 | "CallExpression.UnaryExpression": 1, 17 | "CatchClause": 1, 18 | "ClassDeclaration": 1, 19 | "ClassExpression": 1, 20 | "CommentInsideEmptyBlock": 1, 21 | "ConditionalExpression": 1, 22 | "DoWhileStatement": 1, 23 | "ExportNamedDeclaration": 1, 24 | "ForInStatement": 1, 25 | "ForOfStatement": 1, 26 | "ForStatement": 1, 27 | "FunctionDeclaration": 1, 28 | "FunctionExpression": 1, 29 | "IfStatement": 1, 30 | "ImportDeclaration": 1, 31 | "MemberExpression": 1, 32 | "MultipleVariableDeclaration": 1, 33 | "NewExpression": 1, 34 | "ObjectExpression": 1, 35 | "ObjectExpression.BinaryExpression": 1, 36 | "ObjectExpression.LogicalExpression": 1, 37 | "ObjectExpression.UnaryExpression": 1, 38 | "ObjectPattern": 1, 39 | "ParameterList": 1, 40 | "ReturnStatement": 1, 41 | "SingleVariableDeclaration": 0, 42 | "SwitchCase": 1, 43 | "SwitchStatement": 1, 44 | "TopLevelFunctionBlock": 1, 45 | "TryStatement": 1, 46 | "VariableDeclaration.BinaryExpression": 1, 47 | "VariableDeclaration.LogicalExpression": 1, 48 | "VariableDeclaration.UnaryExpression": 1, 49 | "WhileStatement": 1 50 | } 51 | }; 52 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | var limit = require('../limit'); 9 | 10 | exports.format = function(node) { 11 | var braceStart = _tk.findPrev(node.startToken, _tk.isCode); 12 | var braceEnd = _tk.findNext(node.endToken, _tk.isCode); 13 | 14 | // handle `import foo, { lorem, ipsum } from 'lib';` 15 | if (braceStart.value === '{') { 16 | limit.around(braceStart, 'ModuleSpecifierOpeningBrace'); 17 | } else if (braceStart.value === ',') { 18 | limit.around(braceStart, 'ModuleSpecifierComma'); 19 | } 20 | 21 | if (braceEnd.value === ',') { 22 | limit.around(braceEnd, 'ModuleSpecifierComma'); 23 | } else if (braceEnd.value === '}') { 24 | limit.before(braceEnd, 'ModuleSpecifierClosingBrace'); 25 | 26 | var next = _tk.findNextNonEmpty(braceEnd); 27 | if (next && next.value === ';') { 28 | // handle `export {foo, bar};` 29 | _br.limitAfter(braceEnd, 0); 30 | } else if (node.parent.endToken !== braceEnd) { 31 | // we don't want to limit line break for lines that contains just 32 | // `export {foo, bar}` because that would remove undesired line breaks 33 | limit.after(braceEnd, 'ModuleSpecifierClosingBrace'); 34 | } 35 | } 36 | 37 | if (node.startToken.value !== node.endToken.value) { 38 | // handle spaces around "as" 39 | // eg: `import { named1 as myNamed1 } from 'lib'` 40 | // eg: `import * as myLib from 'lib'` 41 | _br.limitAfter(node.startToken, 0); 42 | _br.limitBefore(node.endToken, 0); 43 | _ws.limitAfter(node.startToken, 1); 44 | _ws.limitBefore(node.endToken, 1); 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /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 | var consequent = node.consequent[0]; 22 | if (consequent && consequent.type === 'BlockStatement') { 23 | limit.around(consequent.startToken, 'SwitchCaseBlockStart'); 24 | limit.around(consequent.endToken, 'SwitchCaseBlockEnd'); 25 | } 26 | 27 | // endToken might be ":" or "break" or ";" 28 | var breakKeyword = _tk.findInBetweenFromEnd(node.startToken, endToken.next, 'break'); 29 | if (breakKeyword) { 30 | limit.before(breakKeyword, 'BreakKeyword'); 31 | limit.after(endToken, 'BreakKeyword'); 32 | } 33 | }; 34 | 35 | 36 | exports.getIndentEdges = function(node) { 37 | // we need to get the next token because `default` might end with a `}` 38 | // (ie. IfStatement) we also need to search for next `case` or `}` or 39 | // `break` or `default` to make sure comments are included inside the range 40 | var consequent = node.consequent[0]; 41 | var end = consequent && consequent.type === 'BlockStatement' ? 42 | consequent.endToken : 43 | _tk.findNext(node.endToken, ['}', 'case', 'break', 'default']); 44 | return { 45 | startToken: node.startToken, 46 | endToken: end.prev 47 | }; 48 | }; 49 | -------------------------------------------------------------------------------- /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 | 95 | var asyncFunctionExpression = async function() {}; 96 | -------------------------------------------------------------------------------- /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 bar = ipsum; 9 | 10 | var a, 11 | b = true, 12 | c = 3, 13 | d = false; 14 | 15 | var amet = qwe(); 16 | var asi = true 17 | 18 | 19 | // test for issue #4 20 | var 21 | // foo var 22 | foo, 23 | // bar variable 24 | bar = 'dolor amet'; 25 | 26 | 27 | // issue #28 : comma first 28 | var x = 33, 29 | y = 12, 30 | 31 | 32 | // comment 33 | w = 45; 34 | 35 | 36 | // issue #31: multiple var declaration + function expression = wrong indent 37 | (function() { 38 | var 39 | // A central reference to the root jQuery(document) 40 | rootjQuery, 41 | 42 | // Define a local copy of jQuery 43 | jQuery = function(selector, context) { 44 | // The jQuery object is actually just the init constructor 'enhanced' 45 | return new jQuery.fn.init(selector, context, rootjQuery); 46 | }, 47 | 48 | // literal object 49 | obj = { 50 | num: 123, 51 | str: 'literal' 52 | }; 53 | }()); 54 | 55 | var lorem = ipsum || 56 | dolor && 57 | (sit || amet); 58 | 59 | // issue #306: UnaryExpression 60 | var hasNativeRequestAnimationFrame = !!( 61 | window.requestAnimationFrame || 62 | window.webkitRequestAnimationFrame || 63 | window.mozRequestAnimationFrame || 64 | window.msRequestAnimationFrame 65 | ); 66 | 67 | // issue #334 68 | var a = 'foo'; 69 | var b = '3'; 70 | 71 | // comma-first + asi 72 | var foo = 123, 73 | bar = 456; 74 | [1, 2, 3].forEach(echo) 75 | 76 | // issue #382 77 | function getInverseAnswer() { 78 | var a = 10, 79 | b = 4, 80 | answer, 81 | inverse; 82 | answer = a * b + (a - b - b); 83 | inverse = answer * -1; 84 | return inverse; 85 | } 86 | 87 | // issue #416 88 | var foo = bar + baz + 89 | barbaz; 90 | -------------------------------------------------------------------------------- /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/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 | var arrow = tk.findPrev(node.body.startToken, '=>'); 27 | edges.push({ 28 | startToken: arrow, 29 | endToken: node.endToken 30 | }); 31 | } 32 | if (shouldHandleParams(node)) { 33 | edges.push(_params.getIndentEdges(node, opts)); 34 | } 35 | return edges; 36 | }; 37 | 38 | function shouldHandleParams(node) { 39 | var arrow = tk.findPrev(node.body.startToken, '=>'); 40 | // we don't check based on `node.params` because of `node.defaults` 41 | return tk.findPrevNonEmpty(arrow).value === ')'; 42 | } 43 | 44 | function shouldIndentBody(node, opts) { 45 | var bodyFirstNonEmpty = tk.findNextNonEmpty(node.body.startToken); 46 | 47 | if (bodyFirstNonEmpty.value === '}') { 48 | // noop 49 | limit.after(node.body.startToken, 0); 50 | return false; 51 | } else { 52 | // we don't want to indent the body twice if ObjectExpression or 53 | // ArrayExpression or CallExpression 54 | return node.body.type === 'BlockStatement' || !opts[node.body.type]; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /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 bar 9 | = ipsum; 10 | 11 | var a,b= true, 12 | c =3, d=false; 13 | 14 | var 15 | 16 | amet= qwe(); 17 | var asi = true 18 | 19 | 20 | // test for issue #4 21 | var 22 | // foo var 23 | foo, 24 | // bar variable 25 | bar = 'dolor amet'; 26 | 27 | 28 | // issue #28 : comma first 29 | var x=33 30 | ,y=12 31 | 32 | 33 | // comment 34 | , w = 45; 35 | 36 | 37 | // issue #31: multiple var declaration + function expression = wrong indent 38 | (function(){ 39 | var 40 | // A central reference to the root jQuery(document) 41 | rootjQuery, 42 | 43 | // Define a local copy of jQuery 44 | jQuery = function( selector, context ) { 45 | // The jQuery object is actually just the init constructor 'enhanced' 46 | return new jQuery.fn.init( selector, context, rootjQuery ); 47 | }, 48 | 49 | // literal object 50 | obj = { 51 | num : 123, 52 | str : 'literal' 53 | }; 54 | }()); 55 | 56 | var lorem = ipsum || 57 | dolor && 58 | (sit || amet); 59 | 60 | // issue #306: UnaryExpression 61 | var hasNativeRequestAnimationFrame = !!( 62 | window.requestAnimationFrame || 63 | window.webkitRequestAnimationFrame || 64 | window.mozRequestAnimationFrame || 65 | window.msRequestAnimationFrame 66 | ); 67 | 68 | // issue #334 69 | var a = 'foo' ; 70 | var b = '3' 71 | ; 72 | 73 | // comma-first + asi 74 | var foo = 123 75 | , bar = 456 76 | ;[1,2,3].forEach(echo) 77 | 78 | // issue #382 79 | function getInverseAnswer() { 80 | var a = 10, b=4,answer,inverse; 81 | answer = a * b + (a - b - b); 82 | inverse = answer * -1; 83 | return inverse; 84 | } 85 | 86 | // issue #416 87 | var foo = bar + baz + 88 | barbaz; 89 | -------------------------------------------------------------------------------- /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 | 90 | var asyncFunctionExpression = async function() {}; 91 | -------------------------------------------------------------------------------- /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 | exports.getIndentEdges = function(node, opts) { 30 | // we bypass indentation if argument already adds indentation 31 | if ( 32 | !node.argument || 33 | opts[node.argument.type] || 34 | node.argument.type === 'UnaryExpression' 35 | ) { 36 | return false; 37 | } 38 | 39 | // handle agument wrapped in parenthesis 40 | var argumentStart = _tk.findNextNonEmpty(node.startToken); 41 | if (argumentStart.value === '(') { 42 | return { 43 | startToken: argumentStart, 44 | endToken: node.endToken.value === ')' ? 45 | node.endToken : 46 | _tk.findPrevNonEmpty(_tk.findPrev(node.endToken, ')')) 47 | }; 48 | } 49 | 50 | return { 51 | startToken: node.startToken.next, 52 | endToken: _tk.isEmpty(node.endToken) ? 53 | _tk.findPrevNonEmpty(node.endToken) : 54 | node.endToken 55 | }; 56 | }; 57 | -------------------------------------------------------------------------------- /doc/presets.md: -------------------------------------------------------------------------------- 1 | # Presets 2 | 3 | Presets are reusable config files that can `require` other presets/plugins and 4 | override configs. 5 | 6 | ## Reusing presets 7 | 8 | On your [esformatter config file](./config.md) you can do; 9 | 10 | ```js 11 | { 12 | // presets are used as "base settings" 13 | "extends": [ 14 | "preset:foobar", // load "esformatter-preset-foobar" from "./node_modules" 15 | "./lorem_ipsum.json" // load relative config file 16 | ], 17 | 18 | // you can still override any setting from the preset if needed 19 | "indent": { 20 | "value": " " 21 | } 22 | } 23 | ``` 24 | 25 | Note that the `preset:` pseudo-protocol will try to find the module with the 26 | `esformatter-preset-` prefix. That should make it easier to find presets on npm. 27 | 28 | 29 | ## Authoring presets 30 | 31 | List all the preset dependencies on the `package.json`, that way consumers of 32 | your preset only need to list the preset as dependency: 33 | 34 | ```js 35 | { 36 | // use the `esformatter-preset-` prefix on the name 37 | "name": "esformatter-preset-foobar", 38 | // list all the dependencies 39 | "dependencies": { 40 | "esformatter-quotes": "^1.0.3", 41 | "esformatter-preset-dolor": "^1.0.0" 42 | } 43 | } 44 | ``` 45 | 46 | And the implementation would be something like: 47 | 48 | ```js 49 | // need to use `require` because dependencies will be listed 50 | // on the preset "package.json" 51 | module.exports = { 52 | 53 | // extend other presets 54 | extends: [ 55 | require('esformatter-preset-dolor'), 56 | require('./foo-settings') 57 | ], 58 | 59 | // register plugins 60 | plugins: [ 61 | require('esformatter-quotes') 62 | ], 63 | 64 | // this will override any values set by the `esformatter-preset-dolor` and 65 | // `./foo-settings` 66 | indent: { 67 | value: '\t' 68 | } 69 | }; 70 | ``` 71 | 72 | protip: we use this feature on [lib/preset/default.js](../lib/preset/default.js) 73 | to increase organization. 74 | -------------------------------------------------------------------------------- /lib/preset/jquery.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | "extends": [ 5 | require('./default') 6 | ], 7 | 8 | "indent": { 9 | "value": "\t", 10 | "IfStatementConditional": 2, 11 | "SwitchStatement": 0, 12 | "TopLevelFunctionBlock": 0 13 | }, 14 | 15 | "lineBreak": { 16 | "before": { 17 | "ObjectExpressionOpeningBrace": -1, 18 | "ObjectExpressionClosingBrace": -1, 19 | "Property": -1, 20 | "VariableDeclarationWithoutInit": 0 21 | }, 22 | 23 | "after": { 24 | "AssignmentOperator": -1, 25 | "ObjectExpressionOpeningBrace": -1, 26 | "ObjectExpressionClosingBrace": -1, 27 | "Property": -1 28 | } 29 | }, 30 | 31 | "whiteSpace": { 32 | "before": { 33 | "ArgumentList": 1, 34 | "ArrayExpressionClosing": 1, 35 | "CatchParameterList": 1, 36 | "ExpressionClosingParentheses": 1, 37 | "ForInStatementExpressionClosing": 1, 38 | "ForOfStatementExpressionClosing": 1, 39 | "ForStatementExpressionClosing": 1, 40 | "IfStatementConditionalClosing": 1, 41 | "IIFEClosingParentheses": 1, 42 | "MemberExpressionClosing": 1, 43 | "ObjectExpressionClosingBrace": 1, 44 | "ParameterList": 1, 45 | "SwitchDiscriminantClosing": 1, 46 | "WhileStatementConditionalClosing": 1 47 | }, 48 | "after": { 49 | "ArgumentList": 1, 50 | "ArrayExpressionOpening": 1, 51 | "CatchParameterList": 1, 52 | "ExpressionOpeningParentheses": 1, 53 | "ForInStatementExpressionOpening": 1, 54 | "ForOfStatementExpressionOpening": 1, 55 | "ForStatementExpressionOpening": 1, 56 | "IfStatementConditionalOpening": 1, 57 | "IIFEOpeningParentheses": 1, 58 | "MemberExpressionOpening": 1, 59 | "ObjectExpressionOpeningBrace": 1, 60 | "ParameterList": 1, 61 | "PropertyValue": -1, 62 | "SwitchDiscriminantOpening": 1, 63 | "WhileStatementConditionalOpening": 1 64 | } 65 | } 66 | }; 67 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 (i) { 23 | // safer to find based on startToken, because of Flow types 24 | var prev = _tk.findPrevNonEmpty(param.startToken); 25 | if (prev.value === ',') { 26 | _limit.around(prev, 'ParameterComma'); 27 | } 28 | } 29 | 30 | // Default parameters are AssignmentExpressions as params 31 | if (param.type === 'AssignmentPattern' && param.right) { 32 | _limit.around(_tk.findPrev(param.right.startToken, '='), 'AssignmentPattern'); 33 | } 34 | }); 35 | _ws.limitAfter(_tk.findPrevNonEmpty(closing), 'ParameterList'); 36 | } else { 37 | _limit.after(opening, 0); 38 | } 39 | }; 40 | 41 | exports.getIndentEdges = function(node, opts) { 42 | var params = node.params; 43 | if (params.length && opts.ParameterList) { 44 | // get/set on ObjectEpression affect drastically the FunctionExpression 45 | // structure so we need to handle it differently 46 | var start = node.parent.type === 'Property' ? 47 | node.parent.startToken : 48 | node.startToken; 49 | return { 50 | // we check if start is equal to "(" because of arrow functions 51 | startToken: start.value === '(' ? start : _tk.findNext(start, '('), 52 | endToken: _tk.findPrev(node.body.startToken, ')'), 53 | level: opts.ParameterList 54 | }; 55 | } 56 | return null; 57 | }; 58 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lib/format.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _options = require('./options'); 4 | 5 | var npmRun = require('npm-run'); 6 | var parser = require('esformatter-parser'); 7 | var plugins = require('./plugins'); 8 | var transform = require('./transform'); 9 | 10 | exports = module.exports = format; 11 | function format(str, opts) { 12 | // we need to load and register the plugins as soon as possible otherwise 13 | // `stringBefore` won't be called and default settings won't be used 14 | _options.set(opts); 15 | 16 | // remove shebang before pipe because piped commands might not know how 17 | // to handle it 18 | var prefix = getShebang(str); 19 | if (prefix && !_options.get('esformatter.allowShebang')) { 20 | throw new Error( 21 | 'shebang not allowed! Set esformatter.allowShebang to true if you ' + 22 | 'want to support it.' 23 | ); 24 | } 25 | str = str.replace(prefix, ''); 26 | 27 | var pipeCommands = _options.get('pipe'); 28 | 29 | if (pipeCommands) { 30 | str = pipe(pipeCommands.before, str).toString(); 31 | } 32 | 33 | str = doFormat(str, opts); 34 | 35 | if (pipeCommands) { 36 | str = pipe(pipeCommands.after, str).toString(); 37 | } 38 | 39 | // we only restore bang after pipe because piped commands might not know how 40 | // to handle it 41 | return prefix + str; 42 | } 43 | 44 | 45 | // allows users to override parser if needed 46 | exports.parseFn = function(str, opts) { 47 | return parser.parse(str, opts); 48 | }; 49 | 50 | 51 | exports.parseOptions = parser.defaultOptions; 52 | 53 | 54 | function getShebang(str) { 55 | var result = (/^#!.+\n/).exec(str); 56 | return result ? result[0] : ''; 57 | } 58 | 59 | 60 | function doFormat(str) { 61 | str = plugins.stringBefore(str); 62 | // allows user to override the parser 63 | var ast = exports.parseFn(str, exports.parseOptions); 64 | transform(ast, transform.BYPASS_OPTIONS); 65 | str = ast.toString(); 66 | str = plugins.stringAfter(str); 67 | return str; 68 | } 69 | 70 | 71 | // run cli tools in series passing the stdout of previous tool as stdin of next 72 | // one 73 | function pipe(commands, input) { 74 | if (!commands) { 75 | return input; 76 | } 77 | return commands.reduce(function(input, cmd) { 78 | return npmRun.sync(cmd, { 79 | input: input 80 | }); 81 | }, input); 82 | } 83 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------