svger-cli 4.0.1 → 4.0.3

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.
Files changed (41) hide show
  1. package/CHANGELOG.md +230 -0
  2. package/README.md +27 -27
  3. package/dist/builder.d.ts +6 -3
  4. package/dist/builder.js +34 -24
  5. package/dist/cli.js +122 -10
  6. package/dist/config.d.ts +8 -2
  7. package/dist/config.js +17 -124
  8. package/dist/core/enhanced-plugin-manager.d.ts +1 -0
  9. package/dist/core/enhanced-plugin-manager.js +37 -11
  10. package/dist/core/framework-templates.js +4 -0
  11. package/dist/core/logger.js +8 -4
  12. package/dist/core/performance-engine.js +16 -3
  13. package/dist/core/style-compiler.js +6 -7
  14. package/dist/core/template-manager.js +18 -14
  15. package/dist/index.d.ts +1 -2
  16. package/dist/index.js +8 -2
  17. package/dist/integrations/jest-preset.js +30 -2
  18. package/dist/lock.js +1 -1
  19. package/dist/optimizers/basic-cleaner.js +4 -0
  20. package/dist/optimizers/path-parser.js +199 -115
  21. package/dist/optimizers/path-simplifier.js +27 -24
  22. package/dist/optimizers/remove-unused-defs.js +16 -0
  23. package/dist/optimizers/shape-conversion.js +22 -27
  24. package/dist/optimizers/style-optimizer.js +5 -0
  25. package/dist/optimizers/svg-tree-parser.js +4 -0
  26. package/dist/optimizers/transform-collapsing.js +11 -15
  27. package/dist/optimizers/transform-optimizer.js +20 -21
  28. package/dist/optimizers/types.js +64 -74
  29. package/dist/plugins/gradient-optimizer.js +4 -0
  30. package/dist/processors/svg-processor.js +28 -10
  31. package/dist/services/config.js +28 -11
  32. package/dist/services/file-watcher.js +8 -3
  33. package/dist/services/svg-service.d.ts +1 -1
  34. package/dist/services/svg-service.js +24 -11
  35. package/dist/utils/native.d.ts +0 -1
  36. package/dist/utils/native.js +6 -14
  37. package/dist/utils/visual-diff.js +7 -2
  38. package/dist/watch.js +4 -3
  39. package/docs/ERROR-HANDLING-STANDARD.md +111 -0
  40. package/docs/OPTIONAL-DEPENDENCIES.md +1 -1
  41. package/package.json +1 -1
@@ -62,7 +62,6 @@ export class FileSystem {
62
62
  static _readdir = promisify(fs.readdir);
63
63
  static _stat = promisify(fs.stat);
64
64
  static _mkdir = promisify(fs.mkdir);
65
- static _rmdir = promisify(fs.rmdir);
66
65
  static _unlink = promisify(fs.unlink);
67
66
  static async exists(path) {
68
67
  try {
@@ -94,18 +93,7 @@ export class FileSystem {
94
93
  }
95
94
  static async removeDir(dirPath) {
96
95
  try {
97
- const files = await this._readdir(dirPath);
98
- for (const file of files) {
99
- const filePath = `${dirPath}/${file}`;
100
- const stats = await this._stat(filePath);
101
- if (stats.isDirectory()) {
102
- await this.removeDir(filePath);
103
- }
104
- else {
105
- await this._unlink(filePath);
106
- }
107
- }
108
- await this._rmdir(dirPath);
96
+ await fs.promises.rm(dirPath, { recursive: true, force: true });
109
97
  }
110
98
  catch (error) {
111
99
  if (error.code !== 'ENOENT') {
@@ -311,10 +299,14 @@ export class FileWatcher {
311
299
  this.emit(eventType, `${path}/${filename}`);
312
300
  }
313
301
  });
302
+ watcher.on('error', error => {
303
+ this.emit('error', error);
304
+ });
314
305
  this.watchers.push(watcher);
315
306
  }
316
307
  catch (error) {
317
- console.error(`Failed to watch ${path}:`, error);
308
+ // Emit error event so consumers can handle it
309
+ this.emit('error', error);
318
310
  }
319
311
  return this;
320
312
  }
@@ -81,17 +81,22 @@ export class VisualDiffError extends Error {
81
81
  export async function renderSVG(svgContent, config) {
82
82
  await loadVisualDiffDependencies();
83
83
  const renderConfig = { ...DEFAULT_RENDER_CONFIG, ...config };
84
+ const RENDER_TIMEOUT_MS = 30000; // 30 seconds
84
85
  try {
85
86
  // Create SVG buffer
86
87
  const svgBuffer = Buffer.from(svgContent, 'utf-8');
87
- // Render to PNG using sharp
88
- const pngBuffer = await sharp(svgBuffer, { density: renderConfig.density })
88
+ // Render to PNG using sharp with timeout protection
89
+ const renderPromise = sharp(svgBuffer, { density: renderConfig.density })
89
90
  .resize(renderConfig.width, renderConfig.height, {
90
91
  fit: 'contain',
91
92
  background: renderConfig.background,
92
93
  })
93
94
  .png()
94
95
  .toBuffer();
96
+ const timeoutPromise = new Promise((_resolve, reject) => {
97
+ setTimeout(() => reject(new Error(`Render timeout after ${RENDER_TIMEOUT_MS}ms`)), RENDER_TIMEOUT_MS);
98
+ });
99
+ const pngBuffer = await Promise.race([renderPromise, timeoutPromise]);
95
100
  return pngBuffer;
96
101
  }
97
102
  catch (error) {
package/dist/watch.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import path from 'path';
2
2
  import { generateSVG } from './builder.js';
3
3
  import { isLocked } from './lock.js';
4
- import { FileSystem, FileWatcher } from './utils/native.js';
4
+ import { FileSystem, FileWatcher, toPascalCase } from './utils/native.js';
5
5
  /**
6
6
  * Watches a source folder for changes to SVG files and automatically
7
7
  * rebuilds React components when SVGs are added, modified, or deleted.
@@ -59,8 +59,9 @@ export async function watchSVGs(config) {
59
59
  await generateSVG({ svgFile: filePath, outDir });
60
60
  }
61
61
  else {
62
- // File was deleted
63
- const componentName = path.basename(filePath, '.svg');
62
+ // File was deleted — use PascalCase to match the generated component filename
63
+ const baseName = path.basename(filePath, '.svg');
64
+ const componentName = toPascalCase(baseName);
64
65
  const outFile = path.join(outDir, `${componentName}.tsx`);
65
66
  if (await FileSystem.exists(outFile)) {
66
67
  await FileSystem.unlink(outFile);
@@ -0,0 +1,111 @@
1
+ # Error Handling Standards
2
+
3
+ ## Purpose
4
+ This document establishes standardized error handling patterns for SVGER-CLI v4.0.3+ to ensure consistency, proper error propagation, and appropriate user feedback.
5
+
6
+ ## Standard Patterns
7
+
8
+ ### 1. CLI Command Error Handling (Process Exit Required)
9
+ **Pattern:** Log error + exit with code 1
10
+ ```typescript
11
+ try {
12
+ await someOperation();
13
+ } catch (error) {
14
+ logger.error('Operation failed:', error);
15
+ process.exit(1);
16
+ }
17
+ ```
18
+
19
+ ### 2. Service Method Error Handling (Propagate to Caller)
20
+ **Pattern:** Log error + throw
21
+ ```typescript
22
+ try {
23
+ const result = await operation();
24
+ return result;
25
+ } catch (error) {
26
+ logger.error('Failed to perform operation:', error);
27
+ throw error;
28
+ }
29
+ ```
30
+
31
+ ### 3. Background/Async Error Handling (Non-blocking)
32
+ **Pattern:** Log error + return error state
33
+ ```typescript
34
+ try {
35
+ await backgroundTask();
36
+ } catch (error) {
37
+ logger.error('Background task failed:', error);
38
+ return { success: false, error };
39
+ }
40
+ ```
41
+
42
+ ### 4. Batch Processing Error Handling (Continue on Individual Failures)
43
+ **Pattern:** Log individual errors + collect results
44
+ ```typescript
45
+ const results = [];
46
+ for (const item of items) {
47
+ try {
48
+ const result = await processItem(item);
49
+ results.push({ success: true, data: result });
50
+ } catch (error) {
51
+ logger.error(`Failed to process ${item}:`, error);
52
+ results.push({ success: false, error });
53
+ }
54
+ }
55
+ ```
56
+
57
+ ### 5. Plugin Error Handling (Isolated Failure)
58
+ **Pattern:** Log error + skip plugin + continue pipeline
59
+ ```typescript
60
+ try {
61
+ await plugin.execute();
62
+ } catch (error) {
63
+ logger.error(`Plugin "${plugin.name}" failed:`, (error as Error).message);
64
+ // Continue with next plugin
65
+ }
66
+ ```
67
+
68
+ ## Error Types by Severity
69
+
70
+ ### Critical (Process Exit)
71
+ - Configuration file corruption
72
+ - Permission denied for required directories
73
+ - Invalid CLI arguments
74
+
75
+ ### High (Throw Error)
76
+ - File not found for specific operation
77
+ - Invalid SVG syntax
78
+ - Build failures
79
+
80
+ ### Medium (Log + Return Error State)
81
+ - Individual file processing failures in batch
82
+ - Plugin execution failures
83
+ - Optional feature failures (visual validation)
84
+
85
+ ### Low (Log Warning + Continue)
86
+ - Missing optional configuration
87
+ - Deprecation warnings
88
+ - Non-critical file operations
89
+
90
+ ## Implementation Status
91
+
92
+ ### ✅ Completed
93
+ - CLI commands properly exit on error
94
+ - Service methods properly propagate errors
95
+ - Batch processing collects individual failures
96
+
97
+ ### 🔄 Needs Review
98
+ - Ensure all catch blocks follow appropriate pattern for their context
99
+ - Verify error messages are clear and actionable
100
+ - Check that error context is preserved in stack traces
101
+
102
+ ## Related Fixes
103
+ - Bug #2: Added process.exit(1) in config command
104
+ - Bug #12: Plugin registration now throws on duplicate names
105
+ - Bug #17: Added CLI argument validation with early exit
106
+
107
+ ## Next Steps
108
+ 1. Audit all catch blocks for consistency
109
+ 2. Ensure error messages are user-friendly
110
+ 3. Add error codes for common scenarios
111
+ 4. Consider using error-handler.ts more consistently
@@ -158,4 +158,4 @@ If you encounter any issues with optional dependencies:
158
158
 
159
159
  ---
160
160
 
161
- **Last Updated**: January 28, 2026 (v4.0.1)
161
+ **Last Updated**: January 28, 2026 (v4.0.3)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svger-cli",
3
- "version": "4.0.1",
3
+ "version": "4.0.3",
4
4
  "description": "Enterprise-grade SVG to component converter with advanced plugin system, visual diff testing, and official framework integrations. Supporting React, React Native, Vue, Angular, Svelte, Solid, Lit, Preact & Vanilla. Features TypeScript, HMR, optimization pipeline, and extensible architecture.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",