11import { doc } from 'prettier' ;
2- import { isNextLineEmpty , isPrettier2 } from './util.js' ;
2+ import {
3+ isFirst ,
4+ isLast ,
5+ isNextLineEmpty ,
6+ isPrettier2 ,
7+ next ,
8+ previous
9+ } from './backward-compatibility.js' ;
310
411const { group, indent, join, line, softline, hardline } = doc . builders ;
512
@@ -26,12 +33,28 @@ export const printComments = (node, path, options, filter = () => true) => {
2633 // since it depends on the version of Prettier being used.
2734 // Mocking the behaviour will introduce a lot of maintenance in the tests.
2835 /* c8 ignore start */
29- return isPrettier2 ( )
36+ return isPrettier2
3037 ? document . parts // Prettier V2
3138 : document ; // Prettier V3
3239 /* c8 ignore stop */
3340} ;
3441
42+ const shouldHaveEmptyLine = ( node , checkForLeading ) =>
43+ Boolean (
44+ // if node is not FunctionDefinition, it should have an empty line
45+ node . type !== 'FunctionDefinition' ||
46+ // if FunctionDefinition is not abstract, it should have an empty line
47+ node . body ||
48+ // if FunctionDefinition has the comment we are looking for (trailing or
49+ // leading), it should have an empty line
50+ node . comments ?. some ( ( comment ) => checkForLeading && comment . leading )
51+ ) ;
52+
53+ const separatingLine = ( firstNode , secondNode ) =>
54+ shouldHaveEmptyLine ( firstNode , false ) || shouldHaveEmptyLine ( secondNode , true )
55+ ? hardline
56+ : '' ;
57+
3558export function printPreservingEmptyLines ( path , key , options , print ) {
3659 const parts = [ ] ;
3760 path . each ( ( childPath , index ) => {
@@ -48,29 +71,41 @@ export function printPreservingEmptyLines(path, key, options, print) {
4871 parts . push ( hardline ) ;
4972 }
5073
51- if ( index > 0 ) {
52- if (
53- [ 'ContractDefinition' , 'FunctionDefinition' ] . includes ( nodeType ) &&
54- parts [ parts . length - 2 ] !== hardline
55- ) {
74+ // Only attempt to prepend an empty line if `node` is not the first item
75+ // and an empty line hasn't already been appended after the previous `node`
76+ if (
77+ ! isFirst ( childPath , key , index ) &&
78+ parts [ parts . length - 2 ] !== hardline
79+ ) {
80+ if ( nodeType === 'FunctionDefinition' ) {
81+ // Prepend FunctionDefinition with an empty line if there should be a
82+ // separation with the previous `node`
83+ parts . push ( separatingLine ( previous ( childPath , key , index ) , node ) ) ;
84+ } else if ( nodeType === 'ContractDefinition' ) {
85+ // Prepend ContractDefinition with an empty line
5686 parts . push ( hardline ) ;
5787 }
5888 }
5989
6090 parts . push ( print ( childPath ) ) ;
6191
62- if (
63- isNextLineEmpty ( options . originalText , options . locEnd ( node ) + 1 ) ||
64- nodeType === 'FunctionDefinition'
65- ) {
66- parts . push ( hardline ) ;
92+ // Only attempt to append an empty line if `node` is not the last item
93+ if ( ! isLast ( childPath , key , index ) ) {
94+ if ( isNextLineEmpty ( options . originalText , options . locEnd ( node ) + 1 ) ) {
95+ // Append an empty line if the original text already had an one after
96+ // the current `node`
97+ parts . push ( hardline ) ;
98+ } else if ( nodeType === 'FunctionDefinition' ) {
99+ // Append FunctionDefinition with an empty line if there should be a
100+ // separation with the next `node`
101+ parts . push ( separatingLine ( node , next ( childPath , key , index ) ) ) ;
102+ } else if ( nodeType === 'ContractDefinition' ) {
103+ // Append ContractDefinition with an empty line
104+ parts . push ( hardline ) ;
105+ }
67106 }
68107 } , key ) ;
69108
70- if ( parts . length > 1 && parts [ parts . length - 1 ] === hardline ) {
71- parts . pop ( ) ;
72- }
73-
74109 return parts ;
75110}
76111
0 commit comments