@@ -7,6 +7,10 @@ import type {Data, Entry} from './console';
7
7
import * as format from './format' ;
8
8
import markdownTable from './markdownTable' ;
9
9
10
+ const MAX_CHARACTERS_PER_FILE = 65536 ;
11
+ const FILE_SIZE_SAFETY_MARGIN = 1000 ;
12
+ const MAX_CHARACTERS_PER_FILE_WITH_SAFETY_MARGIN = MAX_CHARACTERS_PER_FILE - FILE_SIZE_SAFETY_MARGIN ;
13
+
10
14
const tableHeader = [ 'Name' , 'Duration' ] ;
11
15
12
16
const collapsibleSection = ( title : string , content : string ) => `<details>\n<summary>${ title } </summary>\n\n${ content } \n</details>\n\n` ;
@@ -45,15 +49,27 @@ const formatEntryDuration = (entry: Entry): string => {
45
49
return '' ;
46
50
} ;
47
51
48
- const buildDetailsTable = ( entries : Entry [ ] ) => {
52
+ const buildDetailsTable = ( entries : Entry [ ] , numberOfTables = 1 ) => {
49
53
if ( ! entries . length ) {
50
- return '' ;
54
+ return [ '' ] ;
51
55
}
52
56
53
- const rows = entries . map ( ( entry ) => [ entry . name , buildDurationDetailsEntry ( entry ) ] ) ;
54
- const content = markdownTable ( [ tableHeader , ...rows ] ) ;
57
+ const entriesPerTable = Math . floor ( entries . length / numberOfTables ) ;
58
+ const tables : string [ ] = [ ] ;
59
+ for ( let i = 0 ; i < numberOfTables ; i ++ ) {
60
+ const start = i * entriesPerTable ;
61
+ const end = i === numberOfTables - 1 ? entries . length : start + entriesPerTable ;
62
+ const tableEntries = entries . slice ( start , end ) ;
63
+
64
+ const rows = tableEntries . map ( ( entry ) => [ entry . name , buildDurationDetailsEntry ( entry ) ] ) ;
65
+ const content = markdownTable ( [ tableHeader , ...rows ] ) ;
66
+
67
+ const tableMarkdown = collapsibleSection ( 'Show details' , content ) ;
55
68
56
- return collapsibleSection ( 'Show details' , content ) ;
69
+ tables . push ( tableMarkdown ) ;
70
+ }
71
+
72
+ return tables ;
57
73
} ;
58
74
59
75
const buildSummaryTable = ( entries : Entry [ ] , collapse = false ) => {
@@ -67,36 +83,75 @@ const buildSummaryTable = (entries: Entry[], collapse = false) => {
67
83
return collapse ? collapsibleSection ( 'Show entries' , content ) : content ;
68
84
} ;
69
85
70
- const buildMarkdown = ( data : Data , skippedTests : string [ ] ) => {
71
- let result = '## Performance Comparison Report 📊' ;
86
+ const buildMarkdown = ( data : Data , skippedTests : string [ ] , numberOfExtraFiles ?: number ) : [ string , ...string [ ] ] => {
87
+ let singleFileOutput : string | undefined ;
88
+ let nExtraFiles = numberOfExtraFiles ?? 0 ;
89
+
90
+ // If the user didn't specify the number of extra files, calculate it based on the size of the single file
91
+ if ( numberOfExtraFiles === undefined ) {
92
+ singleFileOutput = buildMarkdown ( data , skippedTests , 0 ) [ 0 ] ;
93
+ const totalCharacters = singleFileOutput . length ?? 0 ;
94
+
95
+ // If the single file is small enough, return it
96
+ if ( totalCharacters <= MAX_CHARACTERS_PER_FILE_WITH_SAFETY_MARGIN ) {
97
+ return [ singleFileOutput ] ;
98
+ }
99
+
100
+ // Otherwise, calculate the number of extra files needed
101
+ nExtraFiles = Math . ceil ( totalCharacters / MAX_CHARACTERS_PER_FILE_WITH_SAFETY_MARGIN ) ;
102
+ }
103
+
104
+ let mainFile = '## Performance Comparison Report 📊' ;
105
+ mainFile += nExtraFiles > 0 ? ` (1/${ nExtraFiles + 1 } )` : '' ;
72
106
73
107
if ( data . errors ?. length ) {
74
- result += '\n\n### Errors\n' ;
108
+ mainFile += '\n\n### Errors\n' ;
75
109
data . errors . forEach ( ( message ) => {
76
- result += ` 1. 🛑 ${ message } \n` ;
110
+ mainFile += ` 1. 🛑 ${ message } \n` ;
77
111
} ) ;
78
112
}
79
113
80
114
if ( data . warnings ?. length ) {
81
- result += '\n\n### Warnings\n' ;
115
+ mainFile += '\n\n### Warnings\n' ;
82
116
data . warnings . forEach ( ( message ) => {
83
- result += ` 1. 🟡 ${ message } \n` ;
117
+ mainFile += ` 1. 🟡 ${ message } \n` ;
84
118
} ) ;
85
119
}
86
120
87
- result += '\n\n### Significant Changes To Duration' ;
88
- result += `\n${ buildSummaryTable ( data . significance ) } ` ;
89
- result += `\n${ buildDetailsTable ( data . significance ) } ` ;
90
- result += '\n\n### Meaningless Changes To Duration' ;
91
- result += `\n${ buildSummaryTable ( data . meaningless , true ) } ` ;
92
- result += `\n${ buildDetailsTable ( data . meaningless ) } ` ;
93
- result += '\n' ;
94
-
95
121
if ( skippedTests . length > 0 ) {
96
- result += `⚠️ Some tests did not pass successfully, so some results are omitted from final report: ${ skippedTests . join ( ', ' ) } ` ;
122
+ mainFile += `⚠️ Some tests did not pass successfully, so some results are omitted from final report: ${ skippedTests . join ( ', ' ) } ` ;
97
123
}
98
124
99
- return result ;
125
+ mainFile += '\n\n### Significant Changes To Duration' ;
126
+ mainFile += `\n${ buildSummaryTable ( data . significance ) } ` ;
127
+ mainFile += `\n${ buildDetailsTable ( data . significance , 1 ) . at ( 0 ) } ` ;
128
+
129
+ const meaninglessDetailsTables = buildDetailsTable ( data . meaningless , nExtraFiles ) ;
130
+
131
+ if ( nExtraFiles === 0 ) {
132
+ mainFile += '\n\n### Meaningless Changes To Duration' ;
133
+ mainFile += `\n${ buildSummaryTable ( data . meaningless , true ) } ` ;
134
+ mainFile += `\n${ meaninglessDetailsTables . at ( 0 ) } ` ;
135
+
136
+ return [ mainFile ] ;
137
+ }
138
+
139
+ const extraFiles : string [ ] = [ ] ;
140
+ for ( let i = 0 ; i < nExtraFiles ; i ++ ) {
141
+ let extraFile = '## Performance Comparison Report 📊' ;
142
+ extraFile += nExtraFiles > 0 ? ` (${ i + 2 } /${ nExtraFiles + 1 } )` : '' ;
143
+
144
+ extraFile += '\n\n### Meaningless Changes To Duration' ;
145
+ extraFile += nExtraFiles > 0 ? ` (${ i + 1 } /${ nExtraFiles + 1 } )` : '' ;
146
+
147
+ extraFile += `\n${ buildSummaryTable ( data . meaningless , true ) } ` ;
148
+ extraFile += `\n${ meaninglessDetailsTables . at ( i ) } ` ;
149
+ extraFile += '\n' ;
150
+
151
+ extraFiles . push ( extraFile ) ;
152
+ }
153
+
154
+ return [ mainFile , ...extraFiles ] ;
100
155
} ;
101
156
102
157
const writeToFile = ( filePath : string , content : string ) =>
@@ -113,13 +168,24 @@ const writeToFile = (filePath: string, content: string) =>
113
168
throw error ;
114
169
} ) ;
115
170
116
- const writeToMarkdown = ( filePath : string , data : Data , skippedTests : string [ ] ) => {
117
- const markdown = buildMarkdown ( data , skippedTests ) ;
118
- Logger . info ( 'Markdown was built successfully, writing to file...' , markdown ) ;
119
- return writeToFile ( filePath , markdown ) . catch ( ( error ) => {
120
- console . error ( error ) ;
121
- throw error ;
122
- } ) ;
171
+ const writeToMarkdown = ( outputDir : string , data : Data , skippedTests : string [ ] ) => {
172
+ const markdownFiles = buildMarkdown ( data , skippedTests ) ;
173
+ const filesString = markdownFiles . join ( '\n\n' ) ;
174
+ Logger . info ( 'Markdown was built successfully, writing to file...' , filesString ) ;
175
+
176
+ if ( markdownFiles . length === 1 ) {
177
+ return writeToFile ( path . join ( outputDir , 'output1.md' ) , markdownFiles [ 0 ] ) ;
178
+ }
179
+
180
+ return Promise . all (
181
+ markdownFiles . map ( ( file , index ) => {
182
+ const filePath = `${ outputDir } /output-${ index + 1 } .md` ;
183
+ return writeToFile ( filePath , file ) . catch ( ( error ) => {
184
+ console . error ( error ) ;
185
+ throw error ;
186
+ } ) ;
187
+ } ) ,
188
+ ) ;
123
189
} ;
124
190
125
191
export default writeToMarkdown ;
0 commit comments