14
14
* limitations under the License.
15
15
*/
16
16
17
- import { Context , ItemConfig , Compression , OrderedCompressionMap , CompressionMap } from './validation/Condition' ;
17
+ import { Context , Compression , OrderedCompressionValues , maxSize } from './validation/Condition' ;
18
18
import { cpus } from 'os' ;
19
19
import { constants as brotliConstants , brotliCompress , gzip , ZlibOptions } from 'zlib' ;
20
- import { readFile } from './fs' ;
21
- import { LogError , LogReport } from './log' ;
20
+ import { readFile } from './helpers/fs' ;
21
+ import { LogError } from './log/helpers/error' ;
22
+ import { Report } from './log/report' ;
23
+ import { TTYReport } from './log/tty-report' ;
24
+ import { stdout } from 'process' ;
22
25
23
26
const COMPRESSION_CONCURRENCY = cpus ( ) . length ;
24
27
const BROTLI_OPTIONS = {
@@ -31,81 +34,105 @@ const BROTLI_OPTIONS = {
31
34
const GZIP_OPTIONS : ZlibOptions = {
32
35
level : 9 ,
33
36
} ;
34
- const reported : Map < ItemConfig [ 'path' ] , CompressionMap > = new Map ( ) ;
35
37
36
- /**
37
- * Pre-populate the report map
38
- * @param configurations
39
- */
40
- function initReport ( configurations : Context [ 'config' ] ) {
41
- for ( const config of configurations ) {
42
- if ( ! reported . get ( config . originalPath ) ) {
43
- reported . set ( config . originalPath , new Map ( OrderedCompressionMap ) ) ;
44
- }
45
- }
38
+ interface CompressionItem {
39
+ path : string ;
40
+ compression : Compression ;
41
+ maxSize : maxSize ;
46
42
}
47
43
48
44
/**
49
45
* Use the given configuration and actual size to report item filesize.
46
+ * @param report Optional reporter to update with this value
50
47
* @param item Configuration for an Item
51
48
* @param error Error from compressing an Item
52
49
* @param size actual size for this comparison
53
50
*/
54
- function store ( item : ItemConfig , error : Error | null , size : number ) : boolean {
51
+ function store ( report : Report | null , context : Context , item : CompressionItem , error : Error | null , size : number ) : boolean {
55
52
if ( error !== null ) {
56
53
LogError ( `Could not compress '${ item . path } ' with '${ item . compression } '.` ) ;
57
54
return false ;
58
55
}
59
56
60
- let compressionMap : CompressionMap | undefined ;
61
- if ( ( compressionMap = reported . get ( item . originalPath ) ) ) {
62
- compressionMap . set ( item . compression , [ size , item . maxSize ] ) ;
57
+ // Store the size of the item in the compression map.
58
+ const sizeMap = context . compressed . get ( item . path ) ;
59
+ if ( sizeMap === undefined ) {
60
+ LogError ( `Could not find item '${ item . path } ' with '${ item . compression } ' in compression map.` ) ;
61
+ return false ;
62
+ }
63
+ sizeMap [ OrderedCompressionValues . indexOf ( item . compression ) ] [ 0 ] = size ;
64
+
65
+ report ?. update ( context ) ;
66
+ if ( item . maxSize === undefined ) {
67
+ return true ;
63
68
}
64
69
return size < item . maxSize ;
65
70
}
66
71
67
72
/**
68
- * Compress an Item and report status to the console .
69
- * @param item Configuration for an Item.
73
+ * Given a context, compress all Items within splitting work eagly per cpu core to achieve some concurrency .
74
+ * @param context Finalized Valid Context from Configuration
70
75
*/
71
- async function compressor ( item : ItemConfig ) : Promise < boolean > {
72
- const contents = await readFile ( item . path ) ;
73
- if ( contents ) {
74
- const buffer = Buffer . from ( contents , 'utf8' ) ;
76
+ export default async function compress ( context : Context ) : Promise < boolean > {
77
+ /**
78
+ * Compress an Item and report status to the console.
79
+ * @param item Configuration for an Item.
80
+ */
81
+ async function compressor ( item : CompressionItem ) : Promise < boolean > {
82
+ const contents = await readFile ( item . path ) ;
83
+ if ( contents ) {
84
+ const buffer = Buffer . from ( contents , 'utf8' ) ;
75
85
76
- switch ( item . compression ) {
77
- case Compression . BROTLI :
78
- return new Promise ( resolve =>
79
- brotliCompress ( buffer , BROTLI_OPTIONS , ( error : Error | null , result : Buffer ) => resolve ( store ( item , error , result . byteLength ) ) ) ,
80
- ) ;
81
- case Compression . GZIP :
82
- return new Promise ( resolve =>
83
- gzip ( buffer , GZIP_OPTIONS , ( error : Error | null , result : Buffer ) => resolve ( store ( item , error , result . byteLength ) ) ) ,
84
- ) ;
85
- case Compression . NONE :
86
- default :
87
- return store ( item , null , buffer . byteLength ) ;
86
+ switch ( item . compression ) {
87
+ case 'brotli' :
88
+ return new Promise ( resolve =>
89
+ brotliCompress ( buffer , BROTLI_OPTIONS , ( error : Error | null , result : Buffer ) =>
90
+ resolve ( store ( report , context , item , error , result . byteLength ) ) ,
91
+ ) ,
92
+ ) ;
93
+ case 'gzip' :
94
+ return new Promise ( resolve =>
95
+ gzip ( buffer , GZIP_OPTIONS , ( error : Error | null , result : Buffer ) => resolve ( store ( report , context , item , error , result . byteLength ) ) ) ,
96
+ ) ;
97
+ default :
98
+ return store ( report , context , item , null , buffer . byteLength ) ;
99
+ }
88
100
}
89
- }
90
101
91
- return false ;
92
- }
102
+ return false ;
103
+ }
93
104
94
- /**
95
- * Given a context, compress all Items within splitting work eagly per cpu core to achieve some concurrency.
96
- * @param context Finalized Valid Context from Configuration
97
- */
98
- export default async function compress ( context : Context ) : Promise < [ boolean , Map < ItemConfig [ 'path' ] , CompressionMap > ] > {
99
- initReport ( context . config ) ;
105
+ let report : Report | null = null ;
106
+ const toCompress : Array < CompressionItem > = [ ] ;
107
+ for ( const [ path , sizeMapValue ] of context . compressed ) {
108
+ for ( let iterator : number = 0 ; iterator < OrderedCompressionValues . length ; iterator ++ ) {
109
+ const compression : Compression = OrderedCompressionValues [ iterator ] as Compression ;
110
+ const [ size , maxSize ] = sizeMapValue [ iterator ] ;
111
+ if ( compression === 'none' ) {
112
+ await compressor ( { path, compression, maxSize } ) ;
113
+ }
114
+ if ( size !== undefined ) {
115
+ toCompress . push ( {
116
+ path,
117
+ compression,
118
+ maxSize,
119
+ } ) ;
120
+ }
121
+ }
122
+ }
100
123
124
+ report = stdout . isTTY ? new TTYReport ( context ) : new Report ( context ) ;
101
125
let success : boolean = true ;
102
- for ( let iterator : number = 0 ; iterator < context . config . length ; iterator += COMPRESSION_CONCURRENCY ) {
103
- let itemsSuccessful = await Promise . all ( context . config . slice ( iterator , iterator + COMPRESSION_CONCURRENCY ) . map ( compressor ) ) ;
126
+ for ( let iterator : number = 0 ; iterator < toCompress . length ; iterator += COMPRESSION_CONCURRENCY ) {
127
+ if ( iterator === 0 ) {
128
+ report . update ( context ) ;
129
+ }
130
+ let itemsSuccessful = await Promise . all ( toCompress . slice ( iterator , iterator + COMPRESSION_CONCURRENCY ) . map ( compressor ) ) ;
104
131
if ( itemsSuccessful . includes ( false ) ) {
105
132
success = false ;
106
133
}
107
134
}
108
135
109
- LogReport ( context , reported ) ;
110
- return [ success , reported ] ;
136
+ report . end ( ) ;
137
+ return success ;
111
138
}
0 commit comments