image-convert-cli 1.1.6 → 1.2.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/CHANGELOG.md ADDED
@@ -0,0 +1,68 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [1.2.0] - 2026-02-13
6
+
7
+ ### Added
8
+ - SVG support as input format with automatic resize handling
9
+ - Tilde (~) expansion for home directory in file paths
10
+ - CHANGELOG for version tracking
11
+ - Test coverage script (`bun run test:coverage`)
12
+
13
+ ### Tests
14
+ - Unit tests for SVG conversion
15
+ - Unit tests for path completion with tilde expansion
16
+
17
+ ## [1.1.6] - 2026-02-13
18
+
19
+ ### Added
20
+ - MIT license (LICENSE.md)
21
+ - IDE config files to .gitignore
22
+
23
+ ## [1.1.5] - 2025-02-10
24
+
25
+ ### Changed
26
+ - Bump version to 1.1.5
27
+ - Improve documentation
28
+
29
+ ## [1.1.4] - 2025-02-08
30
+
31
+ ### Changed
32
+ - Bump version to 1.1.4
33
+
34
+ ## [1.1.3] - 2025-02-08
35
+
36
+ ### Fixed
37
+ - Use dynamic version from package.json
38
+
39
+ ## [1.1.2] - 2025-02-08
40
+
41
+ ### Added
42
+ - Auto-update flag and confirmation prompt for self-update
43
+ - Batch conversion mode for directories
44
+
45
+ ## [1.1.1] - 2025-02-07
46
+
47
+ ### Added
48
+ - Version command to display CLI version
49
+
50
+ ### Changed
51
+ - Exclude assets from npm package
52
+
53
+ ## [1.1.0] - 2025-02-07
54
+
55
+ ### Added
56
+ - Self-update check command
57
+
58
+ ### Changed
59
+ - Demo video and reorganize assets folder
60
+
61
+ ## [1.0.0] - 2025-02-07
62
+
63
+ ### Added
64
+ - PNG format support for image conversion
65
+ - Prepare project for npm/bun publishing
66
+
67
+ ### Changed
68
+ - Enhance README with installation, usage examples, and development guide
package/dist/index.js CHANGED
@@ -6577,6 +6577,7 @@ import { spawn } from "child_process";
6577
6577
  // src/prompts.ts
6578
6578
  import * as readline3 from "readline";
6579
6579
  import * as fs3 from "fs";
6580
+ import * as os from "os";
6580
6581
  import * as path2 from "path";
6581
6582
 
6582
6583
  // node_modules/@inquirer/core/dist/lib/key.js
@@ -6723,7 +6724,7 @@ var effectScheduler = {
6723
6724
  // node_modules/@inquirer/core/dist/lib/use-state.js
6724
6725
  function useState(defaultValue) {
6725
6726
  return withPointer((pointer) => {
6726
- const setState = AsyncResource2.bind(function setState(newValue) {
6727
+ const setState = AsyncResource2.bind(function setState2(newValue) {
6727
6728
  if (pointer.get() !== newValue) {
6728
6729
  pointer.set(newValue);
6729
6730
  handleChange();
@@ -8322,11 +8323,11 @@ function isSameFormat(sourcePath, targetFormat) {
8322
8323
  }
8323
8324
  return false;
8324
8325
  }
8325
- var SUPPORTED_FORMATS = ["webp", "jpeg", "jpg", "png"];
8326
+ var INPUT_FORMATS = ["webp", "jpeg", "jpg", "png", "svg"];
8326
8327
  function getImageFilesFromDirectory(dirPath) {
8327
8328
  try {
8328
8329
  const entries = fs.readdirSync(dirPath, { withFileTypes: true });
8329
- return entries.filter((entry) => entry.isFile()).map((entry) => path.join(dirPath, entry.name)).filter((filePath) => SUPPORTED_FORMATS.includes(getExtension(filePath)));
8330
+ return entries.filter((entry) => entry.isFile()).map((entry) => path.join(dirPath, entry.name)).filter((filePath) => INPUT_FORMATS.includes(getExtension(filePath)));
8330
8331
  } catch {
8331
8332
  return [];
8332
8333
  }
@@ -8361,7 +8362,11 @@ async function convertImage(sourcePath, destinationPath, format, compress) {
8361
8362
  default:
8362
8363
  throw new Error(`Unsupported format: ${format}`);
8363
8364
  }
8364
- await import_sharp.default(sourcePath).toFormat(sharpFormat, options).toFile(destinationPath);
8365
+ let sharpInstance = import_sharp.default(sourcePath);
8366
+ if (getExtension(sourcePath) === "svg") {
8367
+ sharpInstance = sharpInstance.resize(512, 512, { fit: "inside" });
8368
+ }
8369
+ await sharpInstance.toFormat(sharpFormat, options).toFile(destinationPath);
8365
8370
  const outputSize = fs2.statSync(destinationPath).size;
8366
8371
  const elapsed = Date.now() - startTime;
8367
8372
  return {
@@ -8474,7 +8479,11 @@ function filePathCompleter(line) {
8474
8479
  const trimmed = line.trim();
8475
8480
  const input = trimmed.split(" ")[0] || ".";
8476
8481
  const isDirectoryInput = input.endsWith("/");
8477
- const dir = isDirectoryInput ? input.slice(0, -1) || "." : path2.dirname(input) || ".";
8482
+ let dir = isDirectoryInput ? input.slice(0, -1) || "." : path2.dirname(input) || ".";
8483
+ if (dir === "~" || dir.startsWith("~/")) {
8484
+ const homeDir = os.homedir();
8485
+ dir = dir === "~" ? homeDir : homeDir + dir.slice(1);
8486
+ }
8478
8487
  const base = isDirectoryInput ? "" : path2.basename(input) || "";
8479
8488
  try {
8480
8489
  const files = fs3.readdirSync(dir, { withFileTypes: true });
@@ -8599,6 +8608,7 @@ Options:
8599
8608
  --yes, -y Non-interactive mode (use defaults for optional prompts)
8600
8609
  --source, -s Source file path (required with -y)
8601
8610
  --format, -f Target format: webp, jpeg, jpg, or png (required with -y)
8611
+ Input formats: webp, jpeg, jpg, png, svg
8602
8612
  --dest, -d Destination path (optional, auto-generated if not provided)
8603
8613
  --compress, -c Enable compression (optional, default: false)
8604
8614
 
@@ -8638,7 +8648,7 @@ Conversion settings:`);
8638
8648
  // package.json
8639
8649
  var package_default = {
8640
8650
  name: "image-convert-cli",
8641
- version: "1.1.6",
8651
+ version: "1.2.0",
8642
8652
  license: "MIT",
8643
8653
  type: "module",
8644
8654
  bin: {
@@ -8647,6 +8657,7 @@ var package_default = {
8647
8657
  scripts: {
8648
8658
  start: "bun bin/index.ts",
8649
8659
  test: "bun test",
8660
+ "test:coverage": "bun test --coverage",
8650
8661
  prepare: "husky install",
8651
8662
  build: "bun build ./bin/index.ts --outdir ./dist --target bun",
8652
8663
  publish: "bun run build && bun publish --access public --ignore-scripts"
@@ -8659,7 +8670,7 @@ var package_default = {
8659
8670
  sharp: "^0.34.5"
8660
8671
  },
8661
8672
  devDependencies: {
8662
- "@types/bun": "^1.3.8",
8673
+ "@types/bun": "^1.3.9",
8663
8674
  husky: "^9.1.7"
8664
8675
  },
8665
8676
  repository: {
@@ -8752,7 +8763,7 @@ async function runCli(options, promptService) {
8752
8763
  prompts.showHelp();
8753
8764
  return;
8754
8765
  }
8755
- console.log(`Image Converter - Convert images to webp, jpeg, or jpg
8766
+ console.log(`Image Converter - Convert images between webp, jpeg, jpg, png, and svg
8756
8767
  `);
8757
8768
  const sourcePath = options.source || await prompts.promptSourceFile();
8758
8769
  const targetFormat = options.format || await prompts.promptFormat();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "image-convert-cli",
3
- "version": "1.1.6",
3
+ "version": "1.2.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "bin": {
@@ -9,6 +9,7 @@
9
9
  "scripts": {
10
10
  "start": "bun bin/index.ts",
11
11
  "test": "bun test",
12
+ "test:coverage": "bun test --coverage",
12
13
  "prepare": "husky install",
13
14
  "build": "bun build ./bin/index.ts --outdir ./dist --target bun",
14
15
  "publish": "bun run build && bun publish --access public --ignore-scripts"
@@ -21,7 +22,7 @@
21
22
  "sharp": "^0.34.5"
22
23
  },
23
24
  "devDependencies": {
24
- "@types/bun": "^1.3.8",
25
+ "@types/bun": "^1.3.9",
25
26
  "husky": "^9.1.7"
26
27
  },
27
28
  "repository": {
package/src/cli.ts CHANGED
@@ -118,7 +118,7 @@ export async function runCli(
118
118
  return;
119
119
  }
120
120
 
121
- console.log("Image Converter - Convert images to webp, jpeg, or jpg\n");
121
+ console.log("Image Converter - Convert images between webp, jpeg, jpg, png, and svg\n");
122
122
 
123
123
  const sourcePath = options.source || await prompts.promptSourceFile();
124
124
 
package/src/converter.ts CHANGED
@@ -12,6 +12,7 @@ import {
12
12
  getImageFilesFromDirectory,
13
13
  isSameFormat,
14
14
  ensureDirectoryExists,
15
+ getExtension,
15
16
  } from "./utils/path";
16
17
 
17
18
  export async function convertImage(
@@ -52,7 +53,14 @@ export async function convertImage(
52
53
  }
53
54
 
54
55
  // Perform the conversion
55
- await sharp(sourcePath)
56
+ let sharpInstance = sharp(sourcePath);
57
+
58
+ // For SVG input, resize to get proper output dimensions
59
+ if (getExtension(sourcePath) === "svg") {
60
+ sharpInstance = sharpInstance.resize(512, 512, { fit: "inside" });
61
+ }
62
+
63
+ await sharpInstance
56
64
  .toFormat(sharpFormat, options)
57
65
  .toFile(destinationPath);
58
66
 
package/src/prompts.ts CHANGED
@@ -1,18 +1,27 @@
1
1
  import * as readline from "node:readline";
2
2
  import * as fs from "node:fs";
3
+ import * as os from "node:os";
3
4
  import * as path from "node:path";
4
5
  import { select, confirm } from "@inquirer/prompts";
5
6
  import type { SupportedFormat, ConversionSettings } from "./types";
6
- import { getDefaultDestinationPath } from "./utils/path";
7
7
  import { displayConversionResult } from "./converter";
8
8
 
9
- function filePathCompleter(line: string): readline.CompleterResult {
9
+ export function filePathCompleter(line: string): readline.CompleterResult {
10
10
  const trimmed = line.trim();
11
11
  const input = trimmed.split(" ")[0] || ".";
12
12
 
13
13
  const isDirectoryInput = input.endsWith("/");
14
- const dir = isDirectoryInput ? input.slice(0, -1) || "." : path.dirname(input) || ".";
15
- const base = isDirectoryInput ? "" : (path.basename(input) || "");
14
+ let dir = isDirectoryInput
15
+ ? input.slice(0, -1) || "."
16
+ : path.dirname(input) || ".";
17
+
18
+ // Expand tilde to home directory
19
+ if (dir === "~" || dir.startsWith("~/")) {
20
+ const homeDir = os.homedir();
21
+ dir = dir === "~" ? homeDir : homeDir + dir.slice(1);
22
+ }
23
+
24
+ const base = isDirectoryInput ? "" : path.basename(input) || "";
16
25
 
17
26
  try {
18
27
  const files: fs.Dirent[] = fs.readdirSync(dir, { withFileTypes: true });
@@ -56,7 +65,9 @@ async function inputWithPathCompletion(
56
65
  const validationResult = validate(result);
57
66
  if (validationResult !== true) {
58
67
  console.log(`\nError: ${validationResult}`);
59
- inputWithPathCompletion(message, defaultValue, validate).then(resolve);
68
+ inputWithPathCompletion(message, defaultValue, validate).then(
69
+ resolve,
70
+ );
60
71
  return;
61
72
  }
62
73
  }
@@ -68,16 +79,29 @@ async function inputWithPathCompletion(
68
79
 
69
80
  export interface IPromptService {
70
81
  promptSourceFile(validate?: (path: string) => string | true): Promise<string>;
71
- promptDestination(defaultPath: string, validate?: (path: string) => string | true): Promise<string>;
82
+ promptDestination(
83
+ defaultPath: string,
84
+ validate?: (path: string) => string | true,
85
+ ): Promise<string>;
72
86
  promptFormat(): Promise<SupportedFormat>;
73
87
  promptCompress(): Promise<boolean>;
74
88
  promptConfirm(settings: ConversionSettings): Promise<boolean>;
75
89
  promptForOverwrite(filePath: string): Promise<boolean>;
76
- promptBatchDestination(defaultPath: string, validate?: (path: string) => string | true): Promise<string>;
90
+ promptBatchDestination(
91
+ defaultPath: string,
92
+ validate?: (path: string) => string | true,
93
+ ): Promise<string>;
77
94
  promptBatchConfirm(fileCount: number): Promise<boolean>;
78
95
  showHelp(): void;
79
96
  showSettings(settings: ConversionSettings): void;
80
- showResult(result: { success: boolean; destinationPath: string; elapsed: number; originalSize: number; outputSize: number; error?: string }): void;
97
+ showResult(result: {
98
+ success: boolean;
99
+ destinationPath: string;
100
+ elapsed: number;
101
+ originalSize: number;
102
+ outputSize: number;
103
+ error?: string;
104
+ }): void;
81
105
  }
82
106
 
83
107
  export class InteractivePromptService implements IPromptService {
@@ -197,6 +221,7 @@ Options:
197
221
  --yes, -y Non-interactive mode (use defaults for optional prompts)
198
222
  --source, -s Source file path (required with -y)
199
223
  --format, -f Target format: webp, jpeg, jpg, or png (required with -y)
224
+ Input formats: webp, jpeg, jpg, png, svg
200
225
  --dest, -d Destination path (optional, auto-generated if not provided)
201
226
  --compress, -c Enable compression (optional, default: false)
202
227
 
@@ -222,7 +247,14 @@ Examples:
222
247
  console.log(` Compression: ${settings.compress ? "Yes" : "No"}`);
223
248
  }
224
249
 
225
- showResult(result: { success: boolean; destinationPath: string; elapsed: number; originalSize: number; outputSize: number; error?: string }): void {
250
+ showResult(result: {
251
+ success: boolean;
252
+ destinationPath: string;
253
+ elapsed: number;
254
+ originalSize: number;
255
+ outputSize: number;
256
+ error?: string;
257
+ }): void {
226
258
  displayConversionResult({
227
259
  success: result.success,
228
260
  sourcePath: "",
package/src/utils/path.ts CHANGED
@@ -33,7 +33,7 @@ export function isSameFormat(sourcePath: string, targetFormat: SupportedFormat):
33
33
  return false;
34
34
  }
35
35
 
36
- const SUPPORTED_FORMATS = ["webp", "jpeg", "jpg", "png"];
36
+ export const INPUT_FORMATS = ["webp", "jpeg", "jpg", "png", "svg"];
37
37
 
38
38
  export function getImageFilesFromDirectory(dirPath: string): string[] {
39
39
  try {
@@ -41,7 +41,7 @@ export function getImageFilesFromDirectory(dirPath: string): string[] {
41
41
  return entries
42
42
  .filter((entry) => entry.isFile())
43
43
  .map((entry) => path.join(dirPath, entry.name))
44
- .filter((filePath) => SUPPORTED_FORMATS.includes(getExtension(filePath)));
44
+ .filter((filePath) => INPUT_FORMATS.includes(getExtension(filePath)));
45
45
  } catch {
46
46
  return [];
47
47
  }