svger-cli 4.0.2 → 4.0.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/config.js CHANGED
@@ -1,158 +1,51 @@
1
- import path from 'path';
2
- import { FileSystem } from './utils/native.js';
3
- const CONFIG_FILE = '.svgconfig.json';
4
1
  /**
5
- * Get the absolute path to the configuration file.
2
+ * Legacy configuration module - delegates to ConfigService.
6
3
  *
7
- * @returns {string} Absolute path to .svgconfig.json
4
+ * @deprecated Use `configService` from `./services/config.js` instead.
5
+ * This module exists only for backward compatibility and will be removed in v5.0.0.
8
6
  */
9
- function getConfigPath() {
10
- return path.resolve(CONFIG_FILE);
11
- }
7
+ import { configService } from './services/config.js';
12
8
  /**
13
9
  * Read the current svger-cli configuration.
14
10
  *
15
- * @returns {Record<string, any>} Configuration object. Returns an empty object if no config file exists.
11
+ * @deprecated Use `configService.readConfig()` instead.
12
+ * @returns {Record<string, any>} Configuration object.
16
13
  */
17
14
  export function readConfig() {
18
- return FileSystem.readJSONSync(getConfigPath());
15
+ return configService.readConfig();
19
16
  }
20
17
  /**
21
18
  * Write a configuration object to the config file.
22
19
  *
20
+ * @deprecated Use `configService.writeConfig(config)` instead.
23
21
  * @param {Record<string, any>} config - Configuration object to write.
24
22
  */
25
23
  export function writeConfig(config) {
26
- FileSystem.writeJSONSync(getConfigPath(), config, { spaces: 2 });
24
+ configService.writeConfig(config);
27
25
  }
28
26
  /**
29
27
  * Initialize the svger-cli configuration with default values.
30
- * If a config file already exists, this function will not overwrite it.
28
+ *
29
+ * @deprecated Use `configService.initConfig()` instead.
31
30
  */
32
31
  export async function initConfig() {
33
- if (await FileSystem.exists(getConfigPath())) {
34
- console.log('⚠️ Config file already exists:', getConfigPath());
35
- return;
36
- }
37
- const defaultConfig = {
38
- // Configuration Version (for migration compatibility)
39
- version: '4.0.0',
40
- // Source & Output
41
- source: './src/assets/svg',
42
- output: './src/components/icons',
43
- // Framework Configuration
44
- framework: 'react',
45
- typescript: true,
46
- componentType: 'functional',
47
- // Processing Options
48
- watch: false,
49
- parallel: true,
50
- batchSize: 10,
51
- maxConcurrency: 4,
52
- cache: true,
53
- // Default Properties
54
- defaultWidth: 24,
55
- defaultHeight: 24,
56
- defaultFill: 'currentColor',
57
- defaultStroke: 'none',
58
- defaultStrokeWidth: 1,
59
- // Styling Configuration
60
- styleRules: {
61
- fill: 'inherit',
62
- stroke: 'none',
63
- },
64
- responsive: {
65
- breakpoints: ['sm', 'md', 'lg', 'xl'],
66
- values: {
67
- width: ['16px', '20px', '24px', '32px'],
68
- height: ['16px', '20px', '24px', '32px'],
69
- },
70
- },
71
- theme: {
72
- mode: 'auto',
73
- variables: {
74
- primary: 'currentColor',
75
- secondary: '#6b7280',
76
- accent: '#3b82f6',
77
- },
78
- },
79
- animations: [],
80
- // v4.0.0: Plugin System
81
- plugins: [],
82
- // Advanced Options
83
- exclude: [],
84
- include: [],
85
- // Error Handling
86
- errorHandling: {
87
- strategy: 'continue',
88
- maxRetries: 3,
89
- timeout: 30000,
90
- },
91
- // Performance Settings
92
- performance: {
93
- optimization: 'balanced',
94
- memoryLimit: 512,
95
- cacheTimeout: 3600000,
96
- },
97
- // Output Customization
98
- outputConfig: {
99
- naming: 'pascal',
100
- extension: 'tsx',
101
- directory: './src/components/icons',
102
- },
103
- // Framework-specific configurations
104
- react: {
105
- componentType: 'functional',
106
- forwardRef: true,
107
- memo: false,
108
- propsInterface: 'SVGProps',
109
- styledComponents: false,
110
- cssModules: false,
111
- },
112
- vue: {
113
- api: 'composition',
114
- setup: true,
115
- typescript: true,
116
- scoped: true,
117
- cssVariables: true,
118
- },
119
- angular: {
120
- standalone: true,
121
- signals: true,
122
- changeDetection: 'OnPush',
123
- encapsulation: 'Emulated',
124
- },
125
- // Legacy support (deprecated)
126
- template: {
127
- type: 'default',
128
- },
129
- frameworkOptions: {
130
- forwardRef: true,
131
- memo: false,
132
- scriptSetup: true,
133
- standalone: true,
134
- },
135
- };
136
- writeConfig(defaultConfig);
137
- console.log('✅ Config file created:', getConfigPath());
32
+ return configService.initConfig();
138
33
  }
139
34
  /**
140
35
  * Set a specific configuration key to a new value.
141
36
  *
37
+ * @deprecated Use `configService.setConfig(key, value)` instead.
142
38
  * @param {string} key - The config key to set.
143
39
  * @param {any} value - The value to assign to the key.
144
40
  */
145
41
  export function setConfig(key, value) {
146
- const config = readConfig();
147
- config[key] = value;
148
- writeConfig(config);
149
- console.log(`✅ Set config ${key}=${value}`);
42
+ configService.setConfig(key, value);
150
43
  }
151
44
  /**
152
45
  * Display the current configuration in the console.
46
+ *
47
+ * @deprecated Use `configService.showConfig()` instead.
153
48
  */
154
49
  export function showConfig() {
155
- const config = readConfig();
156
- console.log('📄 Current Config:');
157
- console.log(JSON.stringify(config, null, 2));
50
+ configService.showConfig();
158
51
  }
@@ -19,10 +19,14 @@ export class LoggerService {
19
19
  this.enableColors = enabled;
20
20
  }
21
21
  shouldLog(level) {
22
- const levels = ['debug', 'info', 'warn', 'error'];
23
- const currentIndex = levels.indexOf(this.logLevel);
24
- const messageIndex = levels.indexOf(level);
25
- return messageIndex >= currentIndex;
22
+ // O(1) Map lookup instead of O(n) indexOf on array
23
+ const levelPriority = {
24
+ debug: 0,
25
+ info: 1,
26
+ warn: 2,
27
+ error: 3,
28
+ };
29
+ return (levelPriority[level] ?? 0) >= (levelPriority[this.logLevel] ?? 0);
26
30
  }
27
31
  formatMessage(level, message) {
28
32
  const timestamp = new Date().toISOString();
@@ -1,4 +1,5 @@
1
1
  import os from 'os';
2
+ import fs from 'fs';
2
3
  import { logger } from '../core/logger.js';
3
4
  import { svgProcessor } from '../processors/svg-processor.js';
4
5
  /**
@@ -41,7 +42,12 @@ export class PerformanceEngine {
41
42
  }
42
43
  }
43
44
  const totalDuration = Date.now() - startTime;
44
- const successful = results.filter(r => r.success).length;
45
+ // Single-pass counter instead of results.filter().length O(n) → O(n) but avoids intermediate array allocation
46
+ let successful = 0;
47
+ for (let i = 0; i < results.length; i++) {
48
+ if (results[i].success)
49
+ successful++;
50
+ }
45
51
  logger.info(`Batch processing complete: ${successful}/${files.length} successful in ${totalDuration}ms`);
46
52
  return results;
47
53
  }
@@ -166,8 +172,15 @@ export class PerformanceEngine {
166
172
  }
167
173
  }
168
174
  generateCacheKey(filePath, options) {
169
- // Create a hash of file path and options for caching
170
- const key = JSON.stringify({ filePath, options });
175
+ // Include file modification time to invalidate cache when file changes
176
+ let mtimeMs = 0;
177
+ try {
178
+ mtimeMs = fs.statSync(filePath).mtimeMs;
179
+ }
180
+ catch {
181
+ // File may not exist yet; use 0 so caching still works
182
+ }
183
+ const key = JSON.stringify({ filePath, mtimeMs, options });
171
184
  return Buffer.from(key).toString('base64');
172
185
  }
173
186
  getCachedResult(key) {
@@ -217,13 +217,12 @@ function getAnimationStyles(animationType: string): React.CSSProperties {
217
217
  }
218
218
 
219
219
  function getThemeStyles(theme: _theme): React.CSSProperties {
220
- if (theme === 'dark') {
221
- return { filter: 'invert(1) hue-rotate(180deg)' };
222
- }
223
- if (theme === 'auto') {
224
- return { filter: 'var(--svger-theme-filter, none)' };
225
- }
226
- return {};
220
+ // O(1) object lookup instead of if-else chain
221
+ const themeStyleMap: Record<string, React.CSSProperties> = {
222
+ dark: { filter: 'invert(1) hue-rotate(180deg)' },
223
+ auto: { filter: 'var(--svger-theme-filter, none)' },
224
+ };
225
+ return themeStyleMap[theme as string] || {};
227
226
  }
228
227
 
229
228
  ${componentName}.displayName = "${componentName}";
@@ -424,23 +424,27 @@ const ${componentName} = React.forwardRef<SVGSVGElement, ${componentName}Props>(
424
424
  baseStyles.color = colorMap[variant];
425
425
  }
426
426
 
427
- // Apply theme
428
- if (theme === 'dark') {
429
- baseStyles.filter = 'invert(1)';
430
- } else if (theme === 'auto') {
431
- baseStyles.filter = 'var(--svger-theme-filter, none)';
427
+ // Apply theme — O(1) object lookup instead of if-else chain
428
+ const themeFilters: Record<string, string> = {
429
+ dark: 'invert(1)',
430
+ auto: 'var(--svger-theme-filter, none)',
431
+ };
432
+ if (theme && themeFilters[theme]) {
433
+ baseStyles.filter = themeFilters[theme];
432
434
  }
433
435
 
434
- // Apply animation
436
+ // Apply animation — O(1) object lookup instead of if-else chain
435
437
  if (animate) {
436
- if (animate === true || animate === 'spin') {
437
- baseStyles.animation = 'svger-spin 2s linear infinite';
438
- } else if (animate === 'pulse') {
439
- baseStyles.animation = 'svger-pulse 2s ease-in-out infinite';
440
- } else if (animate === 'bounce') {
441
- baseStyles.animation = 'svger-bounce 1s infinite';
442
- } else if (animate === 'fade') {
443
- baseStyles.animation = 'svger-fade 2s ease-in-out infinite alternate';
438
+ const animationMap: Record<string, string> = {
439
+ spin: 'svger-spin 2s linear infinite',
440
+ pulse: 'svger-pulse 2s ease-in-out infinite',
441
+ bounce: 'svger-bounce 1s infinite',
442
+ fade: 'svger-fade 2s ease-in-out infinite alternate',
443
+ };
444
+ const animKey = animate === true ? 'spin' : animate;
445
+ const anim = animationMap[animKey as string];
446
+ if (anim) {
447
+ baseStyles.animation = anim;
444
448
  }
445
449
  }
446
450
 
package/dist/index.d.ts CHANGED
@@ -4,7 +4,6 @@
4
4
  * A high-performance, framework-agnostic SVG processing toolkit with enterprise-grade
5
5
  * architecture and comprehensive styling capabilities.
6
6
  *
7
- * @version 2.0.0
8
7
  * @author SVGER-CLI Development Team
9
8
  * @license MIT
10
9
  */
@@ -148,7 +147,7 @@ export declare const SVGER: {
148
147
  /**
149
148
  * Package Version Information
150
149
  */
151
- export declare const VERSION = "2.0.0";
150
+ export declare const VERSION: string;
152
151
  export declare const PACKAGE_NAME = "svger-cli";
153
152
  /**
154
153
  * Webpack Plugin - Official webpack integration for SVGER-CLI
package/dist/index.js CHANGED
@@ -4,10 +4,16 @@
4
4
  * A high-performance, framework-agnostic SVG processing toolkit with enterprise-grade
5
5
  * architecture and comprehensive styling capabilities.
6
6
  *
7
- * @version 2.0.0
8
7
  * @author SVGER-CLI Development Team
9
8
  * @license MIT
10
9
  */
10
+ import { readFileSync } from 'fs';
11
+ import { fileURLToPath } from 'url';
12
+ import { dirname, join } from 'path';
13
+ // Get package version dynamically
14
+ const __index_filename = fileURLToPath(import.meta.url);
15
+ const __index_dirname = dirname(__index_filename);
16
+ const __packageJson = JSON.parse(readFileSync(join(__index_dirname, '../package.json'), 'utf-8'));
11
17
  // ============================================================================
12
18
  // CORE SERVICES
13
19
  // ============================================================================
@@ -149,7 +155,7 @@ export const SVGER = {
149
155
  /**
150
156
  * Package Version Information
151
157
  */
152
- export const VERSION = '2.0.0';
158
+ export const VERSION = __packageJson.version;
153
159
  export const PACKAGE_NAME = 'svger-cli';
154
160
  // ============================================================================
155
161
  // BUILD TOOL INTEGRATIONS
@@ -72,12 +72,40 @@ module.exports.default = ${componentName};
72
72
  }
73
73
  },
74
74
  };
75
+ /**
76
+ * Synchronous SVG content cleaning for Jest compatibility.
77
+ * svgProcessor.cleanSVGContent() is async (uses optimizer pipeline) and cannot
78
+ * be called from Jest's synchronous process() method. This provides equivalent
79
+ * basic cleaning without the async optimizer pipeline.
80
+ */
81
+ function cleanSVGContentSync(svgContent) {
82
+ return (svgContent
83
+ // Remove XML declaration
84
+ .replace(/<\?xml.*?\?>/g, '')
85
+ // Remove DOCTYPE declaration
86
+ .replace(/<!DOCTYPE.*?>/g, '')
87
+ // Remove comments
88
+ .replace(/<!--[\s\S]*?-->/g, '')
89
+ // Normalize whitespace
90
+ .replace(/\r?\n|\r/g, '')
91
+ .replace(/\s{2,}/g, ' ')
92
+ // Remove xmlns attributes
93
+ .replace(/\s+xmlns(:xlink)?="[^"]*"/g, '')
94
+ // Remove metadata
95
+ .replace(/<metadata[\s\S]*?<\/metadata>/gi, '')
96
+ .replace(/<title[\s\S]*?<\/title>/gi, '')
97
+ .replace(/<desc[\s\S]*?<\/desc>/gi, '')
98
+ .trim()
99
+ // Extract inner content from <svg> tag
100
+ .replace(/^<svg[^>]*>([\s\S]*)<\/svg>$/i, '$1')
101
+ .trim());
102
+ }
75
103
  /**
76
104
  * Generate component synchronously (for Jest compatibility)
77
105
  */
78
106
  function generateComponentSync(componentName, svgContent, options) {
79
- // Clean SVG content
80
- const cleanedContent = svgProcessor.cleanSVGContent(svgContent);
107
+ // Clean SVG content synchronously (cleanSVGContent is async and cannot be used here)
108
+ const cleanedContent = cleanSVGContentSync(svgContent);
81
109
  // For Jest, we'll generate a simple React component
82
110
  const viewBox = svgProcessor.extractViewBox(svgContent);
83
111
  const template = `