@divriots/jampack 0.2.3 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -94,13 +94,13 @@ function printIssues() {
94
94
  printTitle('Issues', kleur.bgRed);
95
95
  console.log('');
96
96
  for (let [file, list] of $state.issues) {
97
- console.log(kleur.red('▶ ' + file + '\n'));
97
+ console.log('▶ ' + file + '\n');
98
98
  list.forEach(issue => {
99
99
  issueCount++;
100
- console.log(`❌ ${issue.msg}\n`);
100
+ console.log(`${kleur.bgYellow(` ${issue.type} `)} ${issue.msg}\n`);
101
101
  });
102
102
  }
103
+ printTitle(`${issueCount} issue(s) over ${$state.issues.size} files`, kleur.bgYellow);
103
104
  console.log('');
104
- printTitle(`${issueCount} issue(s) over ${$state.issues.size} files`, kleur.bgRed);
105
105
  }
106
106
  }
package/dist/optimize.js CHANGED
@@ -2,14 +2,14 @@ import { globby } from 'globby';
2
2
  import * as path from 'path';
3
3
  import * as fs from 'fs/promises';
4
4
  import cheerio from 'cheerio';
5
- import { isLocal, isNumeric, translateSrc } from './utils.js';
6
- import sharp from "sharp";
5
+ import { isNumeric } from './utils.js';
7
6
  import config from './config.js';
8
7
  import { compressImage } from './compress.js';
9
8
  import svgToMiniDataURI from 'mini-svg-data-uri';
10
9
  import $state from './state.js';
11
10
  import kleur from 'kleur';
12
11
  import ora from 'ora';
12
+ import { isLocal, Resource, translateSrc } from './utils/resource.js';
13
13
  async function analyse(file) {
14
14
  console.log('▶ ' + file);
15
15
  const html = (await fs.readFile(path.join($state.dir, file))).toString();
@@ -49,7 +49,7 @@ async function processImage(htmlfile, $, imgElement) {
49
49
  */
50
50
  const attrib_src = img.attr('src');
51
51
  if (!attrib_src) {
52
- $state.reportIssue(htmlfile, { msg: `Missing [src] on img - processing skipped.` });
52
+ $state.reportIssue(htmlfile, { type: 'warn', msg: `Missing [src] on img - processing skipped.` });
53
53
  return;
54
54
  }
55
55
  /*
@@ -57,7 +57,7 @@ async function processImage(htmlfile, $, imgElement) {
57
57
  */
58
58
  const attrib_alt = img.attr('alt');
59
59
  if (attrib_alt === undefined) {
60
- $state.reportIssue(htmlfile, { msg: `Missing [alt] on img src="${attrib_src}" - Adding alt="" meanwhile.` });
60
+ $state.reportIssue(htmlfile, { type: 'a11y', msg: `Missing [alt] on img src="${attrib_src}" - Adding alt="" meanwhile.` });
61
61
  img.attr('alt', "");
62
62
  }
63
63
  if (attrib_src.startsWith('data:')) {
@@ -65,10 +65,6 @@ async function processImage(htmlfile, $, imgElement) {
65
65
  // TODO: try to compress it
66
66
  return;
67
67
  }
68
- if (!isLocal(attrib_src)) {
69
- // Image not local, don't touch it
70
- return;
71
- }
72
68
  /*
73
69
  * Attribute 'loading'
74
70
  */
@@ -85,49 +81,46 @@ async function processImage(htmlfile, $, imgElement) {
85
81
  // Don't touch it
86
82
  break;
87
83
  default:
88
- $state.reportIssue(htmlfile, { msg: `Invalid [loading]="${attr_loading}" on img src="${attrib_src}"` });
84
+ $state.reportIssue(htmlfile, { type: 'invalid', msg: `Invalid [loading]="${attr_loading}" on img src="${attrib_src}"` });
89
85
  }
90
86
  /*
91
87
  * Attribute 'decoding'
92
88
  */
93
89
  img.attr('decoding', 'async');
90
+ if (!isLocal(attrib_src)) {
91
+ // Image not local, don't touch it
92
+ return;
93
+ }
94
94
  /*
95
95
  * Loading image
96
96
  */
97
- const absoluteImgPath = translateSrc($state.dir, path.dirname(htmlfile), attrib_src);
98
- // file exists?
99
- try {
100
- await fs.stat(absoluteImgPath);
101
- }
102
- catch (e) {
103
- $state.reportIssue(htmlfile, { msg: `Can't find img src="${attrib_src}" in ${absoluteImgPath}` });
97
+ const originalImage = await Resource.loadResource($state.dir, htmlfile, attrib_src);
98
+ // No file -> give up
99
+ if (!originalImage) {
100
+ $state.reportIssue(htmlfile, { type: 'erro', msg: `Can't find img on disk src="${attrib_src}"` });
104
101
  return;
105
102
  }
106
- // Read file
107
- const originalData = await fs.readFile(absoluteImgPath);
108
- const sharpFile = sharp(absoluteImgPath);
109
- const meta = await sharpFile.metadata();
110
103
  /*
111
104
  * Compress image to WebP
112
105
  */
113
106
  let newImage;
114
- if (!$state.optimizedFiles.has(absoluteImgPath)) {
107
+ if (!$state.optimizedFiles.has(originalImage.filePathAbsolute)) {
115
108
  // Let's avoid to optimize same images twice
116
- $state.optimizedFiles.add(absoluteImgPath);
117
- newImage = await compressImage(originalData, {}, true);
118
- if ((newImage === null || newImage === void 0 ? void 0 : newImage.data) && newImage.data.length < originalData.length) {
109
+ $state.optimizedFiles.add(originalImage.filePathAbsolute);
110
+ newImage = await compressImage(await originalImage.getData(), {}, true);
111
+ if ((newImage === null || newImage === void 0 ? void 0 : newImage.data) && newImage.data.length < await originalImage.getLen()) {
119
112
  // Do we need to add an new extension?
120
113
  const newExtension = `.${newImage.format}`;
121
- const additionalExtension = path.extname(absoluteImgPath) === newExtension ? '' : newExtension;
122
- const newFilename = absoluteImgPath + additionalExtension;
114
+ const additionalExtension = path.extname(originalImage.filePathAbsolute) === newExtension ? '' : newExtension;
115
+ const newFilename = originalImage.filePathAbsolute + additionalExtension;
123
116
  if (!$state.args.nowrite) {
124
117
  fs.writeFile(newFilename, newImage.data);
125
118
  }
126
119
  $state.compressedFiles.add(newFilename);
127
120
  // Report compression result
128
121
  $state.reportSummary({
129
- action: (newFilename !== absoluteImgPath) ? `${meta.format}->${newImage.format}` : path.extname(absoluteImgPath),
130
- originalSize: originalData.length,
122
+ action: (newFilename !== originalImage.filePathAbsolute) ? `${await originalImage.getExt()}->${newImage.format}` : path.extname(originalImage.filePathAbsolute),
123
+ originalSize: await originalImage.getLen(),
131
124
  compressedSize: newImage.data.length
132
125
  });
133
126
  img.attr('src', attrib_src + additionalExtension);
@@ -160,17 +153,13 @@ async function processImage(htmlfile, $, imgElement) {
160
153
  img.attr('src', datauri);
161
154
  img.removeAttr('loading');
162
155
  img.removeAttr('decoding');
163
- $state.reportSummary({ action: `${newImage.format}->embed`, originalSize: originalData.length, compressedSize: newImage.data.length });
156
+ $state.reportSummary({ action: `${newImage.format}->embed`, originalSize: await originalImage.getLen(), compressedSize: newImage.data.length });
164
157
  }
165
158
  }
166
159
  /*
167
160
  * Attribute 'width' & 'height'
168
161
  */
169
- const [w, h] = setImageSize(img, meta);
170
- if (w < 0 || h < 0) {
171
- $state.reportIssue(htmlfile, { msg: `Unexpected error in image size calculation src="${attrib_src}" - can't performance some optmizations.` });
172
- return;
173
- }
162
+ const [w, h] = await setImageSize(img, originalImage);
174
163
  if (isEmbed) {
175
164
  // Image is embed, no need for more processing
176
165
  return;
@@ -178,8 +167,9 @@ async function processImage(htmlfile, $, imgElement) {
178
167
  //
179
168
  // Stop here if svg
180
169
  //
181
- if (meta.format === 'svg')
170
+ if (await originalImage.getExt() === 'svg') {
182
171
  return;
172
+ }
183
173
  /*
184
174
  * Attribute 'srcset'
185
175
  */
@@ -208,7 +198,7 @@ async function processImage(htmlfile, $, imgElement) {
208
198
  if (!$state.compressedFiles.has(absoluteFilename)) {
209
199
  // Add file to list avoid recompression
210
200
  $state.compressedFiles.add(absoluteFilename);
211
- const compressedImage = await compressImage(originalData, { width: valueW, height: valueH }, true);
201
+ const compressedImage = await compressImage(await originalImage.getData(), { width: valueW, height: valueH }, true);
212
202
  if ((compressedImage === null || compressedImage === void 0 ? void 0 : compressedImage.data) && !$state.args.nowrite) {
213
203
  fs.writeFile(absoluteFilename, compressedImage.data);
214
204
  }
@@ -224,10 +214,10 @@ async function processImage(htmlfile, $, imgElement) {
224
214
  }
225
215
  }
226
216
  catch (e) {
227
- $state.reportIssue(htmlfile, { msg: `Unexpected error while processing image: ${JSON.stringify(e)}` });
217
+ $state.reportIssue(htmlfile, { type: 'erro', msg: e.message || `Unexpected error while processing image: ${JSON.stringify(e)}` });
228
218
  }
229
219
  }
230
- function setImageSize(img, meta) {
220
+ async function setImageSize(img, image) {
231
221
  let width = img.attr('width');
232
222
  let height = img.attr('height');
233
223
  let width_new = undefined;
@@ -246,8 +236,12 @@ function setImageSize(img, meta) {
246
236
  }
247
237
  }
248
238
  // If we don't have the metadata, we can't do much more
249
- if (meta.width === undefined || meta.height === undefined) {
250
- return [-1, -1];
239
+ const meta = await image.getImageMeta();
240
+ if (!meta) {
241
+ throw new Error(`Can't get image meta information of "${image.src}" - some optimizations are not possible without this information.`);
242
+ }
243
+ if (meta.width === undefined && meta.height === undefined) {
244
+ throw new Error(`Can't get image width and height of "${image.src}" - some optimizations are not possible without this information.`);
251
245
  }
252
246
  const originalRatio = meta.width / meta.height;
253
247
  if (width !== undefined && height !== undefined) {
@@ -274,17 +268,68 @@ function setImageSize(img, meta) {
274
268
  }
275
269
  else {
276
270
  // No width or height provided - set both to image size
277
- width_new = meta.width;
278
- height_new = meta.height;
271
+ if (await image.getExt() === 'svg') {
272
+ // svg with no height and width has special sizing by browsers
273
+ // They size it inside 300x150 unless they have width and height
274
+ // attributes
275
+ // Load svg
276
+ const c = cheerio.load(await image.getData(), {});
277
+ const svg = c('svg').first();
278
+ const svg_viewbox = svg.attr('viewbox'); // bug in cheerio here, should be "viewBox"
279
+ const svg_width = svg.attr('width');
280
+ const svg_height = svg.attr('height');
281
+ // Calculate aspect ratio from viewbox
282
+ let svg_aspectratio_from_viewbox = undefined;
283
+ if (svg_viewbox) {
284
+ const box = svg_viewbox.split(' ');
285
+ const w = parseInt(box[2], 10);
286
+ const h = parseInt(box[3], 10);
287
+ svg_aspectratio_from_viewbox = w / h;
288
+ }
289
+ // Set size
290
+ //
291
+ if (svg_width && isNumeric(svg_width) && svg_height && isNumeric(svg_height)) {
292
+ // height and width are present
293
+ // use them
294
+ width_new = parseInt(svg_width, 10);
295
+ height_new = parseInt(svg_height, 10);
296
+ }
297
+ else if (svg_width === undefined && svg_height === undefined && svg_aspectratio_from_viewbox) {
298
+ // no height and no width but viewbox is present
299
+ // fit it in default browser box 300x150
300
+ if (svg_aspectratio_from_viewbox >= 2) {
301
+ // fit width
302
+ width_new = 300;
303
+ height_new = width_new / svg_aspectratio_from_viewbox;
304
+ }
305
+ else {
306
+ // fit height
307
+ height_new = 150;
308
+ width_new = height_new * svg_aspectratio_from_viewbox;
309
+ }
310
+ }
311
+ else {
312
+ // no width and no height and no viewbox
313
+ // default browser values
314
+ width_new = 300;
315
+ height_new = 150;
316
+ }
317
+ }
318
+ else {
319
+ width_new = meta.width;
320
+ height_new = meta.height;
321
+ }
279
322
  }
280
323
  // New sizes
281
324
  if (width_new !== undefined && height_new !== undefined) {
282
- img.attr('width', width_new.toFixed(0));
283
- img.attr('height', height_new.toFixed(0));
284
- return [Math.round(width_new), Math.round(height_new)];
325
+ const result_w = Math.round(width_new);
326
+ const result_h = Math.round(height_new);
327
+ img.attr('width', result_w.toFixed(0));
328
+ img.attr('height', result_h.toFixed(0));
329
+ return [result_w, result_h];
285
330
  }
286
331
  // Something when wrong
287
- throw new Error('Unexpected issue when resolving image sizes');
332
+ throw new Error(`Unexpected issue when resolving image size "${image.src}"`);
288
333
  }
289
334
  export async function optimize(exclude) {
290
335
  const glob = ['**/*.{htm,html}'];
package/dist/state.d.ts CHANGED
@@ -13,6 +13,7 @@ declare type Summary = {
13
13
  dataLenCompressed: number;
14
14
  };
15
15
  declare type Issue = {
16
+ type: 'invalid' | 'a11y' | 'perf' | 'erro' | 'warn';
16
17
  msg: string;
17
18
  };
18
19
  export declare class GlobalState {
@@ -0,0 +1,31 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ import { FileExtension, MimeType } from 'file-type';
3
+ declare type ImageMeta = {
4
+ width: number | undefined;
5
+ height: number | undefined;
6
+ isProgressive: boolean;
7
+ hasAlpha: boolean;
8
+ };
9
+ /**
10
+ * File extension, mime and data are loaded only on demand, then cached.
11
+ */
12
+ export declare class Resource {
13
+ readonly src: string;
14
+ readonly filePathAbsolute: string;
15
+ private ext;
16
+ private mime;
17
+ private data;
18
+ private image_meta;
19
+ constructor(src: string, filePathAbsolute: string);
20
+ getData(): Promise<Buffer>;
21
+ getImageMeta(): Promise<ImageMeta | null | undefined>;
22
+ getLen(): Promise<number>;
23
+ getExt(): Promise<FileExtension | 'svg'>;
24
+ getMime(): Promise<MimeType | 'image/svg+xml'>;
25
+ private loadFileType;
26
+ static loadResource(projectRoot: string, relativeFile: string, src: string): Promise<Resource | undefined>;
27
+ }
28
+ export declare function isLocal(src: string): boolean;
29
+ export declare function fileExists(path: string): Promise<boolean>;
30
+ export declare function translateSrc(projectRoot: string, htmlRelativePath: string, src: string): string;
31
+ export {};
@@ -0,0 +1,106 @@
1
+ import * as url from 'url';
2
+ import * as path from 'path';
3
+ import * as fs from 'fs/promises';
4
+ import { fileTypeFromBuffer } from 'file-type';
5
+ import sharp from 'sharp';
6
+ /**
7
+ * File extension, mime and data are loaded only on demand, then cached.
8
+ */
9
+ export class Resource {
10
+ constructor(src, filePathAbsolute) {
11
+ this.src = src;
12
+ this.filePathAbsolute = filePathAbsolute;
13
+ }
14
+ async getData() {
15
+ if (this.data === undefined) {
16
+ this.data = await fs.readFile(this.filePathAbsolute);
17
+ }
18
+ return this.data;
19
+ }
20
+ async getImageMeta() {
21
+ if (this.image_meta === undefined) {
22
+ const ext = await this.getExt();
23
+ switch (ext) {
24
+ case 'svg':
25
+ case 'gif':
26
+ case 'jpg':
27
+ case 'png':
28
+ case 'webp':
29
+ case 'tif':
30
+ let sharpFile = await sharp(await this.getData(), { animated: true });
31
+ const meta = await sharpFile.metadata();
32
+ this.image_meta = {
33
+ width: meta.width,
34
+ height: meta.height,
35
+ isProgressive: meta.isProgressive || false,
36
+ hasAlpha: meta.hasAlpha || false
37
+ };
38
+ break;
39
+ }
40
+ }
41
+ if (!this.image_meta) {
42
+ console.log(await this.getExt());
43
+ }
44
+ return this.image_meta;
45
+ }
46
+ async getLen() {
47
+ return (await this.getData()).length;
48
+ }
49
+ async getExt() {
50
+ if (this.ext === undefined) {
51
+ await this.loadFileType();
52
+ }
53
+ return this.ext;
54
+ }
55
+ async getMime() {
56
+ if (this.mime === undefined) {
57
+ await this.loadFileType();
58
+ }
59
+ return this.mime;
60
+ }
61
+ async loadFileType() {
62
+ const fileType = await fileTypeFromBuffer(await this.getData());
63
+ if (this.filePathAbsolute.endsWith('.svg')) {
64
+ this.ext = 'svg';
65
+ this.mime = 'image/svg+xml';
66
+ }
67
+ else if (fileType) {
68
+ this.ext = fileType.ext;
69
+ this.mime = fileType.mime;
70
+ }
71
+ else {
72
+ throw new Error(`Unknown file type "${this.src}"`);
73
+ }
74
+ }
75
+ static async loadResource(projectRoot, relativeFile, src) {
76
+ if (!isLocal(src)) {
77
+ throw new Error('Source should be local');
78
+ }
79
+ const relativePath = path.join(projectRoot, src.startsWith('/') ? '' : path.dirname(relativeFile), src);
80
+ const absolutePath = path.resolve(relativePath);
81
+ if (await fileExists(absolutePath)) {
82
+ return new Resource(src, absolutePath);
83
+ }
84
+ return undefined;
85
+ }
86
+ }
87
+ export function isLocal(src) {
88
+ const u = url.parse(src);
89
+ return !u.host;
90
+ }
91
+ export async function fileExists(path) {
92
+ try {
93
+ await fs.stat(path);
94
+ }
95
+ catch (e) {
96
+ return false;
97
+ }
98
+ return true;
99
+ }
100
+ export function translateSrc(projectRoot, htmlRelativePath, src) {
101
+ if (!isLocal(src)) {
102
+ throw new Error('Source should be local');
103
+ }
104
+ const srcAbsolutePath = path.join(projectRoot, src.startsWith('/') ? '' : htmlRelativePath, src);
105
+ return path.resolve(srcAbsolutePath);
106
+ }
package/dist/utils.d.ts CHANGED
@@ -1,4 +1,2 @@
1
1
  export declare function formatBytes(bytes: number, decimals?: number): string;
2
- export declare function isLocal(src: string): boolean;
3
- export declare function translateSrc(projectRoot: string, htmlRelativePath: string, src: string): string;
4
2
  export declare function isNumeric(value: string): boolean;
package/dist/utils.js CHANGED
@@ -1,5 +1,3 @@
1
- import * as url from 'url';
2
- import * as path from 'path';
3
1
  export function formatBytes(bytes, decimals = 2) {
4
2
  if (!+bytes)
5
3
  return '0 Bytes';
@@ -9,17 +7,6 @@ export function formatBytes(bytes, decimals = 2) {
9
7
  const i = Math.floor(Math.log(bytes) / Math.log(k));
10
8
  return `${(bytes / Math.pow(k, i)).toFixed(dm)} ${sizes[i]}`;
11
9
  }
12
- export function isLocal(src) {
13
- const u = url.parse(src);
14
- return !u.host;
15
- }
16
- export function translateSrc(projectRoot, htmlRelativePath, src) {
17
- if (!isLocal(src)) {
18
- throw new Error('Source should be local');
19
- }
20
- const srcAbsolutePath = path.join(projectRoot, src.startsWith('/') ? '' : htmlRelativePath, src);
21
- return path.resolve(srcAbsolutePath);
22
- }
23
10
  export function isNumeric(value) {
24
11
  return /^\d+$/.test(value);
25
12
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@divriots/jampack",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "Packer for static websites",
5
5
  "author": "Georges Gomes @georges-gomes",
6
6
  "bin": {
@@ -29,6 +29,7 @@
29
29
  "cheerio": "0.22.0",
30
30
  "commander": "^9.4.1",
31
31
  "csso": "^5.0.5",
32
+ "file-type": "^18.0.0",
32
33
  "globby": "^13.1.2",
33
34
  "html-minifier-terser": "^7.0.0",
34
35
  "kleur": "^4.1.5",
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
package/dist/options.d.ts DELETED
@@ -1,30 +0,0 @@
1
- export declare type WebpOptions = {
2
- effort: number;
3
- mode: 'lossless' | 'lossly';
4
- quality: number;
5
- };
6
- export declare type Options = {
7
- image: {
8
- embed_size: number;
9
- srcset_min_width: number;
10
- srcset_max_width: number;
11
- jpeg: {
12
- options: {
13
- quality: number;
14
- mozjpeg: boolean;
15
- };
16
- };
17
- png: {
18
- options: {
19
- compressionLevel: number;
20
- };
21
- };
22
- webp: {
23
- options_lossless: WebpOptions;
24
- options_lossly: WebpOptions;
25
- };
26
- };
27
- };
28
- declare const default_options: Options;
29
- export declare function fast(): void;
30
- export default default_options;
package/dist/options.js DELETED
@@ -1,59 +0,0 @@
1
- const default_options = {
2
- image: {
3
- embed_size: 400,
4
- srcset_min_width: 400,
5
- srcset_max_width: 5120,
6
- jpeg: {
7
- options: {
8
- quality: 80,
9
- mozjpeg: true
10
- }
11
- },
12
- png: {
13
- options: {
14
- compressionLevel: 9,
15
- }
16
- },
17
- webp: {
18
- options_lossless: {
19
- effort: 4,
20
- quality: 80,
21
- mode: 'lossless'
22
- },
23
- options_lossly: {
24
- effort: 4,
25
- quality: 80,
26
- mode: 'lossly'
27
- }
28
- }
29
- }
30
- };
31
- const fast_options_override = {
32
- image: {
33
- embed_size: 0,
34
- srcset_min_width: 1024,
35
- srcset_max_width: 1024,
36
- jpeg: {
37
- options: {
38
- mozjpeg: false
39
- }
40
- },
41
- png: {
42
- options: {
43
- compressionLevel: 0,
44
- }
45
- },
46
- webp: {
47
- options_lossless: {
48
- effort: 0,
49
- },
50
- options_lossly: {
51
- effort: 0,
52
- }
53
- }
54
- }
55
- };
56
- export function fast() {
57
- Object.assign(default_options, fast_options_override);
58
- }
59
- export default default_options;
@@ -1,25 +0,0 @@
1
- export declare type Args = {
2
- nowrite?: boolean;
3
- };
4
- export declare type Result = {
5
- file: string;
6
- originalSize: number;
7
- compressedSize: number;
8
- };
9
- export declare type Summary = {
10
- nbFiles: number;
11
- nbFilesCompressed: number;
12
- dataLenUncompressed: number;
13
- dataLenCompressed: number;
14
- };
15
- export declare class GlobalState {
16
- dir: string;
17
- args: Args;
18
- compressedFiles: Set<string>;
19
- compressedFilesResult: Result[];
20
- summary: Summary;
21
- summaryByExtension: Record<string, Summary>;
22
- addFile(r: Result): void;
23
- }
24
- declare const state: GlobalState;
25
- export default state;
@@ -1,45 +0,0 @@
1
- import path from "path";
2
- export class GlobalState {
3
- constructor() {
4
- this.dir = 'dist';
5
- this.args = {};
6
- this.compressedFiles = new Set();
7
- this.compressedFilesResult = [];
8
- this.summary = {
9
- nbFiles: 0,
10
- nbFilesCompressed: 0,
11
- dataLenCompressed: 0,
12
- dataLenUncompressed: 0
13
- };
14
- this.summaryByExtension = {};
15
- }
16
- addFile(r) {
17
- const isCompressed = r.compressedSize < r.originalSize ? 1 : 0;
18
- this.compressedFiles.add(r.file);
19
- this.compressedFilesResult.push(r);
20
- this.summary.nbFiles++;
21
- state.summary.nbFilesCompressed += isCompressed;
22
- state.summary.dataLenUncompressed += r.originalSize;
23
- state.summary.dataLenCompressed += r.compressedSize;
24
- const ext = path.extname(r.file);
25
- if (ext) {
26
- let summary = this.summaryByExtension[ext];
27
- if (!summary) {
28
- summary = {
29
- nbFiles: 0,
30
- nbFilesCompressed: 0,
31
- dataLenUncompressed: 0,
32
- dataLenCompressed: 0
33
- };
34
- this.summaryByExtension[ext] = summary;
35
- }
36
- summary.nbFiles++;
37
- summary.nbFilesCompressed += isCompressed;
38
- summary.dataLenUncompressed += r.originalSize;
39
- summary.dataLenCompressed += r.compressedSize;
40
- }
41
- }
42
- ;
43
- }
44
- const state = new GlobalState();
45
- export default state;