diginext-img-magic-cli 0.3.2 → 0.5.0

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
@@ -76,6 +76,8 @@ class ImageConverter {
76
76
  }
77
77
  async convertSingleImage(task) {
78
78
  const { inputPath, index, total } = task;
79
+ const startTime = performance.now();
80
+ const startMemory = process.memoryUsage().heapUsed;
79
81
  try {
80
82
  // console.log(`šŸ“ø [${index}/${total}] Processing: ${path.basename(inputPath)}`);
81
83
  const normalizedPath = inputPath.replace(/\\/g, "/");
@@ -86,34 +88,45 @@ class ImageConverter {
86
88
  const outputPath = normalizedPath.replace(this.options.dir, this.outputDirWebp);
87
89
  await promises_1.default.mkdir(path_1.default.dirname(outputPath), { recursive: true });
88
90
  await promises_1.default.copyFile(normalizedPath, outputPath);
91
+ const endTime = performance.now();
92
+ const endMemory = process.memoryUsage().heapUsed;
89
93
  return {
90
94
  success: true,
91
95
  input: inputPath,
92
96
  output: outputPath,
97
+ metrics: {
98
+ durationMs: endTime - startTime,
99
+ memoryUsedMB: (endMemory - startMemory) / 1024 / 1024,
100
+ },
93
101
  };
94
102
  }
95
103
  // Convert image to WebP
96
104
  const webpOutputPath = normalizedPath.replace(this.options.dir, this.outputDirWebp).replace(`.${fileExt}`, ".webp");
97
105
  await promises_1.default.mkdir(path_1.default.dirname(webpOutputPath), { recursive: true });
98
106
  await (0, sharp_1.default)(normalizedPath).webp().toFile(webpOutputPath);
99
- // // Handle thumbnail if requested
100
- // if (this.options.thumb && result.small) {
101
- // const thumbOutputPath = normalizedPath.replace(this.options.dir, this.outputDirThumb).replace(`.${fileExt}`, ".webp");
102
- // await fs.mkdir(path.dirname(thumbOutputPath), { recursive: true });
103
- // await fs.copyFile(result.small, thumbOutputPath);
104
- // await fs.rm(result.small);
105
- // }
107
+ const endTime = performance.now();
108
+ const endMemory = process.memoryUsage().heapUsed;
106
109
  return {
107
110
  success: true,
108
111
  input: inputPath,
109
112
  output: webpOutputPath,
113
+ metrics: {
114
+ durationMs: endTime - startTime,
115
+ memoryUsedMB: (endMemory - startMemory) / 1024 / 1024,
116
+ },
110
117
  };
111
118
  }
112
119
  catch (error) {
120
+ const endTime = performance.now();
121
+ const endMemory = process.memoryUsage().heapUsed;
113
122
  return {
114
123
  success: false,
115
124
  input: inputPath,
116
125
  error: error instanceof Error ? error.message : String(error),
126
+ metrics: {
127
+ durationMs: endTime - startTime,
128
+ memoryUsedMB: (endMemory - startMemory) / 1024 / 1024,
129
+ },
117
130
  };
118
131
  }
119
132
  }
@@ -193,9 +206,14 @@ class ImageConverter {
193
206
  console.warn("āš ļø Warning: Failed to cleanup temp directory:", error);
194
207
  }
195
208
  }
196
- printSummary(results) {
209
+ printSummary(results, totalDurationMs) {
197
210
  const successful = results.filter((r) => r.success).length;
198
211
  const failed = results.filter((r) => !r.success).length;
212
+ // Calculate metrics
213
+ const totalProcessingTime = results.reduce((sum, r) => { var _a; return sum + (((_a = r.metrics) === null || _a === void 0 ? void 0 : _a.durationMs) || 0); }, 0);
214
+ const avgTimePerImage = results.length > 0 ? totalProcessingTime / results.length : 0;
215
+ const maxMemoryUsed = Math.max(...results.map((r) => { var _a; return ((_a = r.metrics) === null || _a === void 0 ? void 0 : _a.memoryUsedMB) || 0; }), 0);
216
+ const currentMemory = process.memoryUsage();
199
217
  console.log("\n" + "=".repeat(50));
200
218
  console.log("šŸ“Š CONVERSION SUMMARY");
201
219
  console.log("=".repeat(50));
@@ -205,6 +223,15 @@ class ImageConverter {
205
223
  if (this.options.thumb) {
206
224
  console.log(`šŸ–¼ļø Thumbnail directory: ${this.outputDirThumb}`);
207
225
  }
226
+ console.log("\n" + "-".repeat(50));
227
+ console.log("ā±ļø PERFORMANCE METRICS");
228
+ console.log("-".repeat(50));
229
+ console.log(`ā±ļø Total wall time: ${(totalDurationMs / 1000).toFixed(2)}s`);
230
+ console.log(`ā±ļø Total processing time: ${(totalProcessingTime / 1000).toFixed(2)}s`);
231
+ console.log(`ā±ļø Avg time per image: ${avgTimePerImage.toFixed(0)}ms`);
232
+ console.log(`šŸ’¾ Peak heap memory: ${(currentMemory.heapUsed / 1024 / 1024).toFixed(2)} MB`);
233
+ console.log(`šŸ’¾ Heap total: ${(currentMemory.heapTotal / 1024 / 1024).toFixed(2)} MB`);
234
+ console.log(`šŸ’¾ RSS (total process): ${(currentMemory.rss / 1024 / 1024).toFixed(2)} MB`);
208
235
  if (failed > 0) {
209
236
  console.log("\nāŒ Failed conversions:");
210
237
  results.filter((r) => !r.success).forEach((r) => console.log(` • ${path_1.default.basename(r.input)}: ${r.error}`));
@@ -212,6 +239,7 @@ class ImageConverter {
212
239
  console.log("=".repeat(50));
213
240
  }
214
241
  async convert() {
242
+ const conversionStartTime = performance.now();
215
243
  try {
216
244
  // Reset state
217
245
  this.results = [];
@@ -219,7 +247,7 @@ class ImageConverter {
219
247
  // Validate input directory
220
248
  await this.validateDirectory();
221
249
  // Get all files
222
- const files = (0, getAllFiles_1.default)(this.options.dir);
250
+ const files = (0, getAllFiles_1.default)(this.options.dir, undefined, this.options.ignore);
223
251
  if (files.length === 0) {
224
252
  console.log("šŸ“‚ No files found in the specified directory.");
225
253
  return;
@@ -238,7 +266,8 @@ class ImageConverter {
238
266
  const results = await this.processWithQueue(files);
239
267
  // Cleanup and summary
240
268
  await this.cleanup();
241
- this.printSummary(results);
269
+ const totalDurationMs = performance.now() - conversionStartTime;
270
+ this.printSummary(results, totalDurationMs);
242
271
  }
243
272
  catch (error) {
244
273
  console.error("šŸ’„ Conversion failed:", error instanceof Error ? error.message : String(error));
@@ -273,6 +302,13 @@ async function parseArguments() {
273
302
  describe: "Number of concurrent workers",
274
303
  type: "number",
275
304
  default: 12,
305
+ })
306
+ .option("ignore", {
307
+ alias: "i",
308
+ describe: "Folder names to ignore (can specify multiple)",
309
+ type: "string",
310
+ array: true,
311
+ default: [],
276
312
  })
277
313
  .help("h")
278
314
  .alias("h", "help")
@@ -283,6 +319,7 @@ async function parseArguments() {
283
319
  thumb: argv.thumb,
284
320
  maxsize: argv.maxsize,
285
321
  concurrency: argv.concurrency,
322
+ ignore: argv.ignore,
286
323
  };
287
324
  }
288
325
  async function main() {
@@ -294,6 +331,9 @@ async function main() {
294
331
  console.log(`šŸ“ Max size: ${options.maxsize}px`);
295
332
  console.log(`šŸ–¼ļø Generate thumbnails: ${options.thumb ? "Yes" : "No"}`);
296
333
  console.log(`⚔ Concurrency: ${options.concurrency}`);
334
+ if (options.ignore && options.ignore.length > 0) {
335
+ console.log(`🚫 Ignoring folders: ${options.ignore.join(", ")}`);
336
+ }
297
337
  console.log("=".repeat(30));
298
338
  const converter = new ImageConverter(options);
299
339
  await converter.convert();
@@ -311,4 +351,3 @@ process.on("unhandledRejection", (reason, promise) => {
311
351
  });
312
352
  // Run the application
313
353
  main();
314
- //# sourceMappingURL=index.js.map
@@ -1,2 +1,2 @@
1
- declare const getAllFiles: (dirPath: string, arrayOfFiles?: Array<string>) => string[];
1
+ declare const getAllFiles: (dirPath: string, arrayOfFiles?: Array<string>, ignoreFolders?: string[]) => string[];
2
2
  export default getAllFiles;
@@ -5,12 +5,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const fs_1 = __importDefault(require("fs"));
7
7
  const path_1 = __importDefault(require("path"));
8
- const getAllFiles = function (dirPath, arrayOfFiles) {
8
+ const getAllFiles = function (dirPath, arrayOfFiles, ignoreFolders) {
9
9
  const files = fs_1.default.readdirSync(dirPath);
10
10
  arrayOfFiles = arrayOfFiles || [];
11
11
  files.forEach(function (file) {
12
12
  if (fs_1.default.statSync(dirPath + "/" + file).isDirectory()) {
13
- arrayOfFiles = getAllFiles(dirPath + "/" + file, arrayOfFiles);
13
+ // Skip ignored folders
14
+ if (ignoreFolders && ignoreFolders.includes(file))
15
+ return;
16
+ arrayOfFiles = getAllFiles(dirPath + "/" + file, arrayOfFiles, ignoreFolders);
14
17
  }
15
18
  else {
16
19
  const __path = path_1.default.join(dirPath, "/", file).replace(/\\/g, "/");
@@ -21,4 +24,3 @@ const getAllFiles = function (dirPath, arrayOfFiles) {
21
24
  return arrayOfFiles;
22
25
  };
23
26
  exports.default = getAllFiles;
24
- //# sourceMappingURL=getAllFiles.js.map
@@ -10,4 +10,3 @@ const isImageSupported = (url) => {
10
10
  return index >= 0;
11
11
  };
12
12
  exports.default = isImageSupported;
13
- //# sourceMappingURL=isImageSupported.js.map
package/esm/index.js CHANGED
@@ -71,6 +71,8 @@ class ImageConverter {
71
71
  }
72
72
  async convertSingleImage(task) {
73
73
  const { inputPath, index, total } = task;
74
+ const startTime = performance.now();
75
+ const startMemory = process.memoryUsage().heapUsed;
74
76
  try {
75
77
  // console.log(`šŸ“ø [${index}/${total}] Processing: ${path.basename(inputPath)}`);
76
78
  const normalizedPath = inputPath.replace(/\\/g, "/");
@@ -81,34 +83,45 @@ class ImageConverter {
81
83
  const outputPath = normalizedPath.replace(this.options.dir, this.outputDirWebp);
82
84
  await fs.mkdir(path.dirname(outputPath), { recursive: true });
83
85
  await fs.copyFile(normalizedPath, outputPath);
86
+ const endTime = performance.now();
87
+ const endMemory = process.memoryUsage().heapUsed;
84
88
  return {
85
89
  success: true,
86
90
  input: inputPath,
87
91
  output: outputPath,
92
+ metrics: {
93
+ durationMs: endTime - startTime,
94
+ memoryUsedMB: (endMemory - startMemory) / 1024 / 1024,
95
+ },
88
96
  };
89
97
  }
90
98
  // Convert image to WebP
91
99
  const webpOutputPath = normalizedPath.replace(this.options.dir, this.outputDirWebp).replace(`.${fileExt}`, ".webp");
92
100
  await fs.mkdir(path.dirname(webpOutputPath), { recursive: true });
93
101
  await sharp(normalizedPath).webp().toFile(webpOutputPath);
94
- // // Handle thumbnail if requested
95
- // if (this.options.thumb && result.small) {
96
- // const thumbOutputPath = normalizedPath.replace(this.options.dir, this.outputDirThumb).replace(`.${fileExt}`, ".webp");
97
- // await fs.mkdir(path.dirname(thumbOutputPath), { recursive: true });
98
- // await fs.copyFile(result.small, thumbOutputPath);
99
- // await fs.rm(result.small);
100
- // }
102
+ const endTime = performance.now();
103
+ const endMemory = process.memoryUsage().heapUsed;
101
104
  return {
102
105
  success: true,
103
106
  input: inputPath,
104
107
  output: webpOutputPath,
108
+ metrics: {
109
+ durationMs: endTime - startTime,
110
+ memoryUsedMB: (endMemory - startMemory) / 1024 / 1024,
111
+ },
105
112
  };
106
113
  }
107
114
  catch (error) {
115
+ const endTime = performance.now();
116
+ const endMemory = process.memoryUsage().heapUsed;
108
117
  return {
109
118
  success: false,
110
119
  input: inputPath,
111
120
  error: error instanceof Error ? error.message : String(error),
121
+ metrics: {
122
+ durationMs: endTime - startTime,
123
+ memoryUsedMB: (endMemory - startMemory) / 1024 / 1024,
124
+ },
112
125
  };
113
126
  }
114
127
  }
@@ -188,9 +201,14 @@ class ImageConverter {
188
201
  console.warn("āš ļø Warning: Failed to cleanup temp directory:", error);
189
202
  }
190
203
  }
191
- printSummary(results) {
204
+ printSummary(results, totalDurationMs) {
192
205
  const successful = results.filter((r) => r.success).length;
193
206
  const failed = results.filter((r) => !r.success).length;
207
+ // Calculate metrics
208
+ const totalProcessingTime = results.reduce((sum, r) => { var _a; return sum + (((_a = r.metrics) === null || _a === void 0 ? void 0 : _a.durationMs) || 0); }, 0);
209
+ const avgTimePerImage = results.length > 0 ? totalProcessingTime / results.length : 0;
210
+ const maxMemoryUsed = Math.max(...results.map((r) => { var _a; return ((_a = r.metrics) === null || _a === void 0 ? void 0 : _a.memoryUsedMB) || 0; }), 0);
211
+ const currentMemory = process.memoryUsage();
194
212
  console.log("\n" + "=".repeat(50));
195
213
  console.log("šŸ“Š CONVERSION SUMMARY");
196
214
  console.log("=".repeat(50));
@@ -200,6 +218,15 @@ class ImageConverter {
200
218
  if (this.options.thumb) {
201
219
  console.log(`šŸ–¼ļø Thumbnail directory: ${this.outputDirThumb}`);
202
220
  }
221
+ console.log("\n" + "-".repeat(50));
222
+ console.log("ā±ļø PERFORMANCE METRICS");
223
+ console.log("-".repeat(50));
224
+ console.log(`ā±ļø Total wall time: ${(totalDurationMs / 1000).toFixed(2)}s`);
225
+ console.log(`ā±ļø Total processing time: ${(totalProcessingTime / 1000).toFixed(2)}s`);
226
+ console.log(`ā±ļø Avg time per image: ${avgTimePerImage.toFixed(0)}ms`);
227
+ console.log(`šŸ’¾ Peak heap memory: ${(currentMemory.heapUsed / 1024 / 1024).toFixed(2)} MB`);
228
+ console.log(`šŸ’¾ Heap total: ${(currentMemory.heapTotal / 1024 / 1024).toFixed(2)} MB`);
229
+ console.log(`šŸ’¾ RSS (total process): ${(currentMemory.rss / 1024 / 1024).toFixed(2)} MB`);
203
230
  if (failed > 0) {
204
231
  console.log("\nāŒ Failed conversions:");
205
232
  results.filter((r) => !r.success).forEach((r) => console.log(` • ${path.basename(r.input)}: ${r.error}`));
@@ -207,6 +234,7 @@ class ImageConverter {
207
234
  console.log("=".repeat(50));
208
235
  }
209
236
  async convert() {
237
+ const conversionStartTime = performance.now();
210
238
  try {
211
239
  // Reset state
212
240
  this.results = [];
@@ -214,7 +242,7 @@ class ImageConverter {
214
242
  // Validate input directory
215
243
  await this.validateDirectory();
216
244
  // Get all files
217
- const files = getAllFiles(this.options.dir);
245
+ const files = getAllFiles(this.options.dir, undefined, this.options.ignore);
218
246
  if (files.length === 0) {
219
247
  console.log("šŸ“‚ No files found in the specified directory.");
220
248
  return;
@@ -233,7 +261,8 @@ class ImageConverter {
233
261
  const results = await this.processWithQueue(files);
234
262
  // Cleanup and summary
235
263
  await this.cleanup();
236
- this.printSummary(results);
264
+ const totalDurationMs = performance.now() - conversionStartTime;
265
+ this.printSummary(results, totalDurationMs);
237
266
  }
238
267
  catch (error) {
239
268
  console.error("šŸ’„ Conversion failed:", error instanceof Error ? error.message : String(error));
@@ -268,6 +297,13 @@ async function parseArguments() {
268
297
  describe: "Number of concurrent workers",
269
298
  type: "number",
270
299
  default: 12,
300
+ })
301
+ .option("ignore", {
302
+ alias: "i",
303
+ describe: "Folder names to ignore (can specify multiple)",
304
+ type: "string",
305
+ array: true,
306
+ default: [],
271
307
  })
272
308
  .help("h")
273
309
  .alias("h", "help")
@@ -278,6 +314,7 @@ async function parseArguments() {
278
314
  thumb: argv.thumb,
279
315
  maxsize: argv.maxsize,
280
316
  concurrency: argv.concurrency,
317
+ ignore: argv.ignore,
281
318
  };
282
319
  }
283
320
  async function main() {
@@ -289,6 +326,9 @@ async function main() {
289
326
  console.log(`šŸ“ Max size: ${options.maxsize}px`);
290
327
  console.log(`šŸ–¼ļø Generate thumbnails: ${options.thumb ? "Yes" : "No"}`);
291
328
  console.log(`⚔ Concurrency: ${options.concurrency}`);
329
+ if (options.ignore && options.ignore.length > 0) {
330
+ console.log(`🚫 Ignoring folders: ${options.ignore.join(", ")}`);
331
+ }
292
332
  console.log("=".repeat(30));
293
333
  const converter = new ImageConverter(options);
294
334
  await converter.convert();
@@ -306,4 +346,3 @@ process.on("unhandledRejection", (reason, promise) => {
306
346
  });
307
347
  // Run the application
308
348
  main();
309
- //# sourceMappingURL=index.js.map
@@ -1,2 +1,2 @@
1
- declare const getAllFiles: (dirPath: string, arrayOfFiles?: Array<string>) => string[];
1
+ declare const getAllFiles: (dirPath: string, arrayOfFiles?: Array<string>, ignoreFolders?: string[]) => string[];
2
2
  export default getAllFiles;
@@ -1,11 +1,14 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
- const getAllFiles = function (dirPath, arrayOfFiles) {
3
+ const getAllFiles = function (dirPath, arrayOfFiles, ignoreFolders) {
4
4
  const files = fs.readdirSync(dirPath);
5
5
  arrayOfFiles = arrayOfFiles || [];
6
6
  files.forEach(function (file) {
7
7
  if (fs.statSync(dirPath + "/" + file).isDirectory()) {
8
- arrayOfFiles = getAllFiles(dirPath + "/" + file, arrayOfFiles);
8
+ // Skip ignored folders
9
+ if (ignoreFolders && ignoreFolders.includes(file))
10
+ return;
11
+ arrayOfFiles = getAllFiles(dirPath + "/" + file, arrayOfFiles, ignoreFolders);
9
12
  }
10
13
  else {
11
14
  const __path = path.join(dirPath, "/", file).replace(/\\/g, "/");
@@ -16,4 +19,3 @@ const getAllFiles = function (dirPath, arrayOfFiles) {
16
19
  return arrayOfFiles;
17
20
  };
18
21
  export default getAllFiles;
19
- //# sourceMappingURL=getAllFiles.js.map
@@ -8,4 +8,3 @@ const isImageSupported = (url) => {
8
8
  return index >= 0;
9
9
  };
10
10
  export default isImageSupported;
11
- //# sourceMappingURL=isImageSupported.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "diginext-img-magic-cli",
3
- "version": "0.3.2",
3
+ "version": "0.5.0",
4
4
  "sideEffects": false,
5
5
  "readme": "README.md",
6
6
  "bin": {
@@ -34,25 +34,15 @@
34
34
  "prebuild:default": "rm -rf dist && rm -rf esm",
35
35
  "release": "npm run build && npm publish",
36
36
  "dev": "npm run prebuild && concurrently \"tsc --module commonjs --outDir dist --watch \"",
37
- "test": "mocha test/*.test.js",
38
37
  "lint": "TIMING=1 eslint src --fix",
39
38
  "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
40
39
  },
41
40
  "dependencies": {
42
- "@types/jest": "29.4.4",
43
- "@types/node": "20.15.0",
44
41
  "async": "3.2.6",
45
- "concurrently": "7.6.0",
46
- "core-js": "3.29.1",
47
42
  "dayjs": "1.11.7",
48
- "diginext-utils": "4.1.2",
49
- "dotenv": "16.0.3",
50
- "esm": "3.2.25",
51
- "jimp": "0.22.4",
43
+ "diginext-utils": "4.1.3",
44
+ "dotenv": "16.6.1",
52
45
  "sharp": "0.34.5",
53
- "tsconfig": "*",
54
- "tsup": "8.5.1",
55
- "typescript": "4.9.5",
56
46
  "yargs": "17.7.1"
57
47
  },
58
48
  "publishConfig": {
@@ -60,11 +50,14 @@
60
50
  },
61
51
  "devDependencies": {
62
52
  "@types/async": "3.2.24",
53
+ "@types/jest": "29.4.4",
54
+ "@types/node": "20.15.0",
63
55
  "@types/yargs": "17.0.22",
56
+ "concurrently": "7.6.0",
64
57
  "eslint": "8.36.0",
65
58
  "eslint-plugin-import": "2.27.5",
66
59
  "esm": "3.2.25",
67
- "mocha": "10.2.0",
68
- "run-script-os": "1.1.6"
60
+ "tsup": "8.5.1",
61
+ "typescript": "4.9.5"
69
62
  }
70
63
  }