diff --git a/.github/workflows/formatter.yml b/.github/workflows/formatter.yml index 2efaed4..715e1ae 100644 --- a/.github/workflows/formatter.yml +++ b/.github/workflows/formatter.yml @@ -23,10 +23,10 @@ jobs: run: git config --global core.autocrlf false - name: Checkout Formatter sources uses: actions/checkout@v1 - - name: Use Node.js 12 + - name: Use Node.js 16 uses: actions/setup-node@v1 with: - node-version: 12 + node-version: 16 - name: Run npm install run: npm ci - name: Install Haxe version ${{ matrix.haxe-version }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 05d8aa6..e88465a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,14 @@ ## dev branch / next version (1.x.x) -- Added `sameLine.ifElseSemicolonNextLine` to allow breaking `if (true) foo; else foo;`, fixes [#612](https://github.com/HaxeCheckstyle/haxe-formatter/issues/612) ([#662](https://github.com/HaxeCheckstyle/haxe-formatter/issues/668)) +- Added `sameLine.ifElseSemicolonNextLine` to allow breaking `if (true) foo; else foo;`, fixes [#612](https://github.com/HaxeCheckstyle/haxe-formatter/issues/612) ([#668](https://github.com/HaxeCheckstyle/haxe-formatter/issues/668)) - Fixed whitespace before null safety operator - Fixed keeping same line for `macro if` expressions - Fixed wrapping with maxLineLength off by one, fixes [#670](https://github.com/HaxeCheckstyle/haxe-formatter/issues/670) ([#671](https://github.com/HaxeCheckstyle/haxe-formatter/issues/671)) - Fixed extends wrapping for interfaces, fixes [#669](https://github.com/HaxeCheckstyle/haxe-formatter/issues/669) +- Fixed empty lines between fields of enum abstract, fixes [#672](https://github.com/HaxeCheckstyle/haxe-formatter/issues/672) ([#673](https://github.com/HaxeCheckstyle/haxe-formatter/issues/673)) +- Fixed empty lines for if with comment, fixes [#556](https://github. ([#673](https://github.com/HaxeCheckstyle/haxe-formatter/issues/673))com/HaxeCheckstyle/haxe-formatter/issues/556) +- Fixed empty lines for block level doc comments, fixes [#511](https://github.com/HaxeCheckstyle/haxe-formatter/issues/51) ([#673](https://github.com/HaxeCheckstyle/haxe-formatter/issues/673)) ## version 1.14.6 (2023-02-22) diff --git a/haxe_libraries/hxnodejs.hxml b/haxe_libraries/hxnodejs.hxml index d6dddaa..7772815 100644 --- a/haxe_libraries/hxnodejs.hxml +++ b/haxe_libraries/hxnodejs.hxml @@ -1,6 +1,6 @@ -# @install: lix --silent download "gh://github.com/HaxeFoundation/hxnodejs#020fde75368cb8ff2d04eeea0b3358c0553de5b7" into hxnodejs/12.0.0/github/020fde75368cb8ff2d04eeea0b3358c0553de5b7 --cp ${HAXE_LIBCACHE}/hxnodejs/12.0.0/github/020fde75368cb8ff2d04eeea0b3358c0553de5b7/src --D hxnodejs=12.0.0 +# @install: lix --silent download "gh://github.com/HaxeFoundation/hxnodejs#504066dc1ba5ad543afa5f6c3ea019f06136a82b" into hxnodejs/12.1.0/github/504066dc1ba5ad543afa5f6c3ea019f06136a82b +-cp ${HAXE_LIBCACHE}/hxnodejs/12.1.0/github/504066dc1ba5ad543afa5f6c3ea019f06136a82b/src +-D hxnodejs=12.1.0 --macro allowPackage('sys') # should behave like other target defines and not be defined in macro context --macro define('nodejs') diff --git a/src/formatter/marker/MarkEmptyLines.hx b/src/formatter/marker/MarkEmptyLines.hx index 378568c..8a0a8a6 100644 --- a/src/formatter/marker/MarkEmptyLines.hx +++ b/src/formatter/marker/MarkEmptyLines.hx @@ -315,7 +315,7 @@ class MarkEmptyLines extends MarkerBase { function findClassAndAbstractFields(c:TokenTree):Array { return c.filterCallback(function(token:TokenTree, index:Int):FilterResult { return switch (token.tok) { - case Kwd(KwdFunction), Kwd(KwdVar): + case Kwd(KwdFunction) | Kwd(KwdVar): FoundSkipSubtree; case Kwd(KwdFinal): FoundSkipSubtree; @@ -646,6 +646,12 @@ class MarkEmptyLines extends MarkerBase { if (prevToken == null) { return; } + if (config.emptyLines.enumAbstractEmptyLines.existingBetweenFields == Keep) { + if (hasEmptyLinesBetweenFields(prevToken, currToken)) { + emptyLinesAfterSubTree(prevToken, 1); + return; + } + } if (prevVar != currVar) { // transition between vars and functions emptyLinesAfterSubTree(prevToken, config.emptyLines.enumAbstractEmptyLines.afterVars); @@ -712,7 +718,8 @@ class MarkEmptyLines extends MarkerBase { if (config.existingBetweenFields == Keep) { if (hasEmptyLinesBetweenFields(prevToken, child)) { emptyLinesAfterSubTree(prevToken, 1); - return; + prevToken = child; + continue; } } emptyLinesAfterSubTree(prevToken, config.betweenFields); @@ -998,6 +1005,9 @@ class MarkEmptyLines extends MarkerBase { if (!found) { continue; } + if (!isField(next)) { + continue; + } switch (config.emptyLines.beforeDocCommentEmptyLines) { case Ignore: case None: @@ -1033,6 +1043,28 @@ class MarkEmptyLines extends MarkerBase { } } + function isField(token:TokenTree):Bool { + if (token == null) { + return false; + } + var parent:TokenTree = token.parent; + if (parent == null) { + return true; + } + return switch (parent.tok) { + case Kwd(KwdAbstract) | Kwd(KwdClass) | Kwd(KwdEnum) | Kwd(KwdInterface) | Kwd(KwdTypedef): + true; + case Kwd(_): + false; + case Dot | DblDot | QuestionDot | Arrow | Comma: + false; + case BkOpen | POpen: + false; + default: + isField(parent); + } + } + function markMultilineComments() { var comments:Array = parsedCode.root.filterCallback(function(token:TokenTree, index:Int):FilterResult { return switch (token.tok) { @@ -1063,21 +1095,32 @@ class MarkEmptyLines extends MarkerBase { parsedCode.root.filterCallback(function(token:TokenTree, index:Int):FilterResult { switch (token.tok) { case Kwd(KwdIf): - if ((token.children != null) && (token.children.length > 0)) { - removeEmptyLinesAroundBlock(token.children[1], config.emptyLines.beforeBlocks, Keep); + if ((token.children != null) && (token.children.length > 1)) { + for (child in token.children) { + switch (child.tok) { + case POpen: + continue; + default: + removeEmptyLinesAroundBlock(child, config.emptyLines.beforeBlocks, Keep); + } + } } var block:Null = token.access().firstOf(Kwd(KwdElse)).previousSibling().token; if (block != null) { removeEmptyLinesAroundBlock(block, Keep, config.emptyLines.afterBlocks); } case Kwd(KwdElse): - removeEmptyLinesAroundBlock(token.getFirstChild(), config.emptyLines.beforeBlocks, Keep); + if (token.children != null) { + for (child in token.children) { + removeEmptyLinesAroundBlock(child, config.emptyLines.beforeBlocks, Keep); + } + } case Kwd(KwdCase), Kwd(KwdDefault): var block:Null = token.access().firstOf(DblDot).firstChild().token; removeEmptyLinesAroundBlock(block, config.emptyLines.beforeBlocks, Keep); case Kwd(KwdFunction): case Kwd(KwdFor): - if ((token.children != null) && (token.children.length > 0)) { + if ((token.children != null) && (token.children.length > 1)) { removeEmptyLinesAroundBlock(token.children[1], config.emptyLines.beforeBlocks, Keep); } case Kwd(KwdDo): diff --git a/test/testcases/emptylines/issue_511_block_level_doc_comments.hxtest b/test/testcases/emptylines/issue_511_block_level_doc_comments.hxtest new file mode 100644 index 0000000..1b92f69 --- /dev/null +++ b/test/testcases/emptylines/issue_511_block_level_doc_comments.hxtest @@ -0,0 +1,39 @@ +{} + +--- + +class Main { + static function main() { + + /** test **/ + foo(); + bar(); + + /** test **/ + + foo(); + + bar(); + + /** test **/ + + } +} + +--- + +class Main { + static function main() { + /** test **/ + foo(); + bar(); + + /** test **/ + + foo(); + + bar(); + + /** test **/ + } +} diff --git a/test/testcases/emptylines/issue_556_if_body_with_comment.hxtest b/test/testcases/emptylines/issue_556_if_body_with_comment.hxtest new file mode 100644 index 0000000..cfcfacc --- /dev/null +++ b/test/testcases/emptylines/issue_556_if_body_with_comment.hxtest @@ -0,0 +1,138 @@ +{} + +--- + +class Main { + static function main() { + if (foo) + + bar; + if (foo) // + + bar; + + if (foo) + + bar; + else + + baz; + if (foo) // + + bar; + else // + + baz; + + if (foo) + + // + + bar; + else + + // + + baz; + + + if (foo) + + // + + // + + bar; + else + + // + + // + + baz; + + if (foo) + + // + + // + + bar; // + else + + // + + // + + baz; // + + if (foo) // + + // + + // + + bar; // + else // + + // + + // + + baz; // + } +} + +--- + +class Main { + static function main() { + if (foo) + bar; + if (foo) // + bar; + + if (foo) + bar; + else + baz; + if (foo) // + bar; + else // + baz; + + if (foo) + // + bar; + else + // + baz; + + if (foo) + // + // + bar; + else + // + // + baz; + + if (foo) + // + // + bar; // + else + // + // + baz; // + + if (foo) // + // + // + bar; // + else // + // + // + baz; // + } +} diff --git a/test/testcases/emptylines/issue_672_enum_fields_emptylines.hxtest b/test/testcases/emptylines/issue_672_enum_fields_emptylines.hxtest new file mode 100644 index 0000000..21f60b8 --- /dev/null +++ b/test/testcases/emptylines/issue_672_enum_fields_emptylines.hxtest @@ -0,0 +1,119 @@ +{ + "emptyLines": { + "beforeDocCommentEmptyLines": "ignore", + "afterFieldsWithDocComments": "ignore", + "enumAbstractEmptyLines": { + "existingBetweenFields": "keep" + } + } +} + +--- + +enum abstract Color(Int) { + /** + * Contains a float representing the red color component. + */ + var R = 0; + + /** + * Contains a float representing the green color component. + */ + var G = 0; + + /** + * Contains a float representing the blue color component. + */ + var B = 0; +} + +enum Color { + /** + * Contains a float representing the red color component. + */ + R; + + /** + * Contains a float representing the green color component. + */ + G; + + /** + * Contains a float representing the blue color component. + */ + B; +} + +class Main { + /** + * Contains a float representing the red color component. + */ + var R = 0; + + /** + * Contains a float representing the green color component. + */ + var G = 0; + + /** + * Contains a float representing the blue color component. + */ + var B = 0; + + static function main() {} +} + +--- + +enum abstract Color(Int) { + /** + * Contains a float representing the red color component. + */ + var R = 0; + + /** + * Contains a float representing the green color component. + */ + var G = 0; + + /** + * Contains a float representing the blue color component. + */ + var B = 0; +} + +enum Color { + /** + * Contains a float representing the red color component. + */ + R; + + /** + * Contains a float representing the green color component. + */ + G; + + /** + * Contains a float representing the blue color component. + */ + B; +} + +class Main { + /** + * Contains a float representing the red color component. + */ + var R = 0; + + /** + * Contains a float representing the green color component. + */ + var G = 0; + + /** + * Contains a float representing the blue color component. + */ + var B = 0; + + static function main() {} +}