svger-cli 2.0.1 → 2.0.2

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 (84) hide show
  1. package/dist/cli.js +0 -0
  2. package/dist/core/error-handler.d.ts +63 -0
  3. package/dist/core/error-handler.js +224 -0
  4. package/dist/core/framework-templates.d.ts +17 -0
  5. package/{src/core/framework-templates.ts → dist/core/framework-templates.js} +100 -137
  6. package/dist/core/logger.d.ts +22 -0
  7. package/dist/core/logger.js +85 -0
  8. package/dist/core/performance-engine.d.ts +67 -0
  9. package/dist/core/performance-engine.js +251 -0
  10. package/dist/core/plugin-manager.d.ts +56 -0
  11. package/dist/core/plugin-manager.js +189 -0
  12. package/dist/core/style-compiler.d.ts +88 -0
  13. package/dist/core/style-compiler.js +466 -0
  14. package/dist/core/template-manager.d.ts +64 -0
  15. package/{src/core/template-manager.ts → dist/core/template-manager.js} +172 -255
  16. package/dist/index.d.ts +151 -0
  17. package/{src/index.ts → dist/index.js} +30 -108
  18. package/dist/processors/svg-processor.d.ts +67 -0
  19. package/dist/processors/svg-processor.js +225 -0
  20. package/dist/services/config.d.ts +55 -0
  21. package/dist/services/config.js +209 -0
  22. package/dist/services/file-watcher.d.ts +54 -0
  23. package/dist/services/file-watcher.js +180 -0
  24. package/dist/services/svg-service.d.ts +81 -0
  25. package/dist/services/svg-service.js +383 -0
  26. package/dist/types/index.d.ts +140 -0
  27. package/dist/types/index.js +4 -0
  28. package/dist/utils/native.d.ts +74 -0
  29. package/dist/utils/native.js +305 -0
  30. package/package.json +9 -10
  31. package/.svgconfig.json +0 -3
  32. package/CODE_OF_CONDUCT.md +0 -79
  33. package/CONTRIBUTING.md +0 -146
  34. package/TESTING.md +0 -143
  35. package/cli-framework.test.js +0 -16
  36. package/cli-test-angular/Arrowbenddownleft.component.ts +0 -27
  37. package/cli-test-angular/Vite.component.ts +0 -27
  38. package/cli-test-angular/index.ts +0 -25
  39. package/cli-test-output/Arrowbenddownleft.vue +0 -33
  40. package/cli-test-output/Vite.vue +0 -33
  41. package/cli-test-output/index.ts +0 -25
  42. package/cli-test-react/Arrowbenddownleft.tsx +0 -39
  43. package/cli-test-react/Vite.tsx +0 -39
  44. package/cli-test-react/index.ts +0 -25
  45. package/cli-test-svelte/Arrowbenddownleft.svelte +0 -22
  46. package/cli-test-svelte/Vite.svelte +0 -22
  47. package/cli-test-svelte/index.ts +0 -25
  48. package/docs/ADR-SVG-INTRGRATION-METHODS-001.adr.md +0 -157
  49. package/docs/ADR-SVG-INTRGRATION-METHODS-002.adr.md +0 -550
  50. package/docs/FRAMEWORK-GUIDE.md +0 -768
  51. package/docs/IMPLEMENTATION-SUMMARY.md +0 -376
  52. package/docs/TDR-SVG-INTRGRATION-METHODS-001.tdr.md +0 -115
  53. package/frameworks.test.js +0 -170
  54. package/my-svgs/ArrowBendDownLeft.svg +0 -6
  55. package/my-svgs/vite.svg +0 -1
  56. package/src/builder.ts +0 -104
  57. package/src/clean.ts +0 -21
  58. package/src/cli.ts +0 -221
  59. package/src/config.ts +0 -81
  60. package/src/core/error-handler.ts +0 -303
  61. package/src/core/logger.ts +0 -104
  62. package/src/core/performance-engine.ts +0 -327
  63. package/src/core/plugin-manager.ts +0 -228
  64. package/src/core/style-compiler.ts +0 -605
  65. package/src/lock.ts +0 -74
  66. package/src/processors/svg-processor.ts +0 -288
  67. package/src/services/config.ts +0 -241
  68. package/src/services/file-watcher.ts +0 -218
  69. package/src/services/svg-service.ts +0 -468
  70. package/src/templates/ComponentTemplate.ts +0 -57
  71. package/src/types/index.ts +0 -169
  72. package/src/utils/native.ts +0 -352
  73. package/src/watch.ts +0 -88
  74. package/test-output-mulit/TestIcon-angular-module.component.ts +0 -26
  75. package/test-output-mulit/TestIcon-angular-standalone.component.ts +0 -27
  76. package/test-output-mulit/TestIcon-lit.ts +0 -35
  77. package/test-output-mulit/TestIcon-preact.tsx +0 -38
  78. package/test-output-mulit/TestIcon-react.tsx +0 -35
  79. package/test-output-mulit/TestIcon-solid.tsx +0 -27
  80. package/test-output-mulit/TestIcon-svelte.svelte +0 -22
  81. package/test-output-mulit/TestIcon-vanilla.ts +0 -37
  82. package/test-output-mulit/TestIcon-vue-composition.vue +0 -33
  83. package/test-output-mulit/TestIcon-vue-options.vue +0 -31
  84. package/tsconfig.json +0 -18
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Professional logging service with configurable levels and formatted output
3
+ */
4
+ export class LoggerService {
5
+ static instance;
6
+ logLevel = 'info';
7
+ enableColors = true;
8
+ constructor() { }
9
+ static getInstance() {
10
+ if (!LoggerService.instance) {
11
+ LoggerService.instance = new LoggerService();
12
+ }
13
+ return LoggerService.instance;
14
+ }
15
+ setLogLevel(level) {
16
+ this.logLevel = level;
17
+ }
18
+ setColors(enabled) {
19
+ this.enableColors = enabled;
20
+ }
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;
26
+ }
27
+ formatMessage(level, message) {
28
+ const timestamp = new Date().toISOString();
29
+ const prefix = this.getPrefix(level);
30
+ return `${timestamp} ${prefix} ${message}`;
31
+ }
32
+ getPrefix(level) {
33
+ if (!this.enableColors) {
34
+ return `[${level.toUpperCase()}]`;
35
+ }
36
+ const colors = {
37
+ debug: '\x1b[36m', // Cyan
38
+ info: '\x1b[34m', // Blue
39
+ warn: '\x1b[33m', // Yellow
40
+ error: '\x1b[31m', // Red
41
+ success: '\x1b[32m', // Green
42
+ };
43
+ const reset = '\x1b[0m';
44
+ const color = colors[level] || colors.info;
45
+ const icons = {
46
+ debug: '🔍',
47
+ info: 'ℹ️',
48
+ warn: '⚠️',
49
+ error: '❌',
50
+ success: '✅',
51
+ };
52
+ const icon = icons[level] || icons.info;
53
+ return `${color}${icon} [${level.toUpperCase()}]${reset}`;
54
+ }
55
+ debug(message, ...args) {
56
+ if (this.shouldLog('debug')) {
57
+ console.debug(this.formatMessage('debug', message), ...args);
58
+ }
59
+ }
60
+ info(message, ...args) {
61
+ if (this.shouldLog('info')) {
62
+ console.info(this.formatMessage('info', message), ...args);
63
+ }
64
+ }
65
+ warn(message, ...args) {
66
+ if (this.shouldLog('warn')) {
67
+ console.warn(this.formatMessage('warn', message), ...args);
68
+ }
69
+ }
70
+ error(message, ...args) {
71
+ if (this.shouldLog('error')) {
72
+ console.error(this.formatMessage('error', message), ...args);
73
+ }
74
+ }
75
+ success(message, ...args) {
76
+ if (this.shouldLog('info')) {
77
+ const timestamp = new Date().toISOString();
78
+ const prefix = this.getPrefix('info');
79
+ const successPrefix = this.enableColors ? '✅ [SUCCESS]' : '[SUCCESS]';
80
+ console.log(`${timestamp} ${successPrefix} ${message}`, ...args);
81
+ }
82
+ }
83
+ }
84
+ // Export singleton instance
85
+ export const logger = LoggerService.getInstance();
@@ -0,0 +1,67 @@
1
+ import { ComponentGenerationOptions } from '../types/index.js';
2
+ /**
3
+ * Performance optimization engine for batch processing and parallel execution
4
+ */
5
+ export declare class PerformanceEngine {
6
+ private static instance;
7
+ private processingCache;
8
+ private readonly cacheTimeout;
9
+ private constructor();
10
+ static getInstance(): PerformanceEngine;
11
+ /**
12
+ * Process multiple SVG files in parallel with optimized batching
13
+ */
14
+ processBatch(files: Array<{
15
+ path: string;
16
+ outputDir: string;
17
+ options?: Partial<ComponentGenerationOptions>;
18
+ }>, config?: {
19
+ batchSize?: number;
20
+ parallel?: boolean;
21
+ maxConcurrency?: number;
22
+ }): Promise<Array<{
23
+ success: boolean;
24
+ filePath: string;
25
+ error?: Error;
26
+ duration: number;
27
+ }>>;
28
+ /**
29
+ * Process single file with caching support
30
+ */
31
+ private processSingleWithCaching;
32
+ /**
33
+ * Optimize SVG content with performance considerations
34
+ */
35
+ optimizeSVGContent(content: string, level?: 'fast' | 'balanced' | 'maximum'): string;
36
+ /**
37
+ * Memory usage monitoring and optimization
38
+ */
39
+ monitorMemoryUsage(): {
40
+ heapUsed: number;
41
+ heapTotal: number;
42
+ external: number;
43
+ cacheSize: number;
44
+ recommendations: string[];
45
+ };
46
+ /**
47
+ * Clear processing cache
48
+ */
49
+ clearCache(): void;
50
+ /**
51
+ * Get performance metrics
52
+ */
53
+ getPerformanceMetrics(): {
54
+ cacheHitRate: number;
55
+ averageProcessingTime: number;
56
+ memoryUsage: any;
57
+ };
58
+ private createBatches;
59
+ private withSemaphore;
60
+ private generateCacheKey;
61
+ private getCachedResult;
62
+ private setCachedResult;
63
+ private applyFastOptimizations;
64
+ private applyBalancedOptimizations;
65
+ private applyMaximumOptimizations;
66
+ }
67
+ export declare const performanceEngine: PerformanceEngine;
@@ -0,0 +1,251 @@
1
+ import { logger } from '../core/logger.js';
2
+ import { svgProcessor } from '../processors/svg-processor.js';
3
+ /**
4
+ * Performance optimization engine for batch processing and parallel execution
5
+ */
6
+ export class PerformanceEngine {
7
+ static instance;
8
+ processingCache = new Map();
9
+ cacheTimeout = 5 * 60 * 1000; // 5 minutes
10
+ constructor() { }
11
+ static getInstance() {
12
+ if (!PerformanceEngine.instance) {
13
+ PerformanceEngine.instance = new PerformanceEngine();
14
+ }
15
+ return PerformanceEngine.instance;
16
+ }
17
+ /**
18
+ * Process multiple SVG files in parallel with optimized batching
19
+ */
20
+ async processBatch(files, config = {}) {
21
+ const { batchSize = 10, parallel = true, maxConcurrency = Math.min(4, require('os').cpus().length) } = config;
22
+ logger.info(`Processing ${files.length} files with ${parallel ? 'parallel' : 'sequential'} execution`);
23
+ const startTime = Date.now();
24
+ const results = [];
25
+ if (!parallel) {
26
+ // Sequential processing for stability
27
+ for (const file of files) {
28
+ const result = await this.processSingleWithCaching(file);
29
+ results.push(result);
30
+ }
31
+ }
32
+ else {
33
+ // Parallel processing with controlled concurrency
34
+ const batches = this.createBatches(files, batchSize);
35
+ for (const batch of batches) {
36
+ const semaphore = new Semaphore(maxConcurrency);
37
+ const batchPromises = batch.map(file => this.withSemaphore(semaphore, () => this.processSingleWithCaching(file)));
38
+ const batchResults = await Promise.all(batchPromises);
39
+ results.push(...batchResults);
40
+ }
41
+ }
42
+ const totalDuration = Date.now() - startTime;
43
+ const successful = results.filter(r => r.success).length;
44
+ logger.info(`Batch processing complete: ${successful}/${files.length} successful in ${totalDuration}ms`);
45
+ return results;
46
+ }
47
+ /**
48
+ * Process single file with caching support
49
+ */
50
+ async processSingleWithCaching(file) {
51
+ const startTime = Date.now();
52
+ const cacheKey = this.generateCacheKey(file.path, file.options || {});
53
+ // Check cache first
54
+ const cached = this.getCachedResult(cacheKey);
55
+ if (cached) {
56
+ logger.debug(`Cache hit for ${file.path}`);
57
+ return {
58
+ success: true,
59
+ filePath: file.path,
60
+ duration: Date.now() - startTime
61
+ };
62
+ }
63
+ try {
64
+ const result = await svgProcessor.processSVGFile(file.path, file.outputDir, file.options);
65
+ // Cache successful results
66
+ if (result.success) {
67
+ this.setCachedResult(cacheKey, result);
68
+ }
69
+ return {
70
+ success: result.success,
71
+ filePath: file.path,
72
+ error: result.error,
73
+ duration: Date.now() - startTime
74
+ };
75
+ }
76
+ catch (error) {
77
+ return {
78
+ success: false,
79
+ filePath: file.path,
80
+ error: error,
81
+ duration: Date.now() - startTime
82
+ };
83
+ }
84
+ }
85
+ /**
86
+ * Optimize SVG content with performance considerations
87
+ */
88
+ optimizeSVGContent(content, level = 'balanced') {
89
+ const startTime = performance.now();
90
+ let optimized = content;
91
+ switch (level) {
92
+ case 'fast':
93
+ // Basic optimizations only
94
+ optimized = this.applyFastOptimizations(content);
95
+ break;
96
+ case 'balanced':
97
+ // Standard optimizations with good performance/quality balance
98
+ optimized = this.applyBalancedOptimizations(content);
99
+ break;
100
+ case 'maximum':
101
+ // Comprehensive optimizations
102
+ optimized = this.applyMaximumOptimizations(content);
103
+ break;
104
+ }
105
+ const duration = performance.now() - startTime;
106
+ const compressionRatio = (1 - optimized.length / content.length) * 100;
107
+ logger.debug(`SVG optimization (${level}): ${compressionRatio.toFixed(1)}% reduction in ${duration.toFixed(2)}ms`);
108
+ return optimized;
109
+ }
110
+ /**
111
+ * Memory usage monitoring and optimization
112
+ */
113
+ monitorMemoryUsage() {
114
+ const memUsage = process.memoryUsage();
115
+ const cacheSize = this.processingCache.size;
116
+ const recommendations = [];
117
+ // Memory usage analysis
118
+ const heapUsedMB = memUsage.heapUsed / 1024 / 1024;
119
+ const heapTotalMB = memUsage.heapTotal / 1024 / 1024;
120
+ if (heapUsedMB > 500) {
121
+ recommendations.push('Consider reducing batch size or enabling sequential processing');
122
+ }
123
+ if (cacheSize > 1000) {
124
+ recommendations.push('Cache size is large, consider clearing old entries');
125
+ }
126
+ if (memUsage.external > 100 * 1024 * 1024) {
127
+ recommendations.push('High external memory usage detected');
128
+ }
129
+ return {
130
+ heapUsed: heapUsedMB,
131
+ heapTotal: heapTotalMB,
132
+ external: memUsage.external / 1024 / 1024,
133
+ cacheSize,
134
+ recommendations
135
+ };
136
+ }
137
+ /**
138
+ * Clear processing cache
139
+ */
140
+ clearCache() {
141
+ this.processingCache.clear();
142
+ logger.debug('Processing cache cleared');
143
+ }
144
+ /**
145
+ * Get performance metrics
146
+ */
147
+ getPerformanceMetrics() {
148
+ // This would be implemented with proper metrics collection
149
+ return {
150
+ cacheHitRate: 0, // Placeholder
151
+ averageProcessingTime: 0, // Placeholder
152
+ memoryUsage: this.monitorMemoryUsage()
153
+ };
154
+ }
155
+ // Private helper methods
156
+ createBatches(items, batchSize) {
157
+ const batches = [];
158
+ for (let i = 0; i < items.length; i += batchSize) {
159
+ batches.push(items.slice(i, i + batchSize));
160
+ }
161
+ return batches;
162
+ }
163
+ async withSemaphore(semaphore, task) {
164
+ await semaphore.acquire();
165
+ try {
166
+ return await task();
167
+ }
168
+ finally {
169
+ semaphore.release();
170
+ }
171
+ }
172
+ generateCacheKey(filePath, options) {
173
+ // Create a hash of file path and options for caching
174
+ const key = JSON.stringify({ filePath, options });
175
+ return Buffer.from(key).toString('base64');
176
+ }
177
+ getCachedResult(key) {
178
+ const cached = this.processingCache.get(key);
179
+ if (!cached)
180
+ return null;
181
+ // Check if cache entry is still valid
182
+ if (Date.now() - cached.timestamp > this.cacheTimeout) {
183
+ this.processingCache.delete(key);
184
+ return null;
185
+ }
186
+ return cached.result;
187
+ }
188
+ setCachedResult(key, result) {
189
+ this.processingCache.set(key, {
190
+ result,
191
+ timestamp: Date.now()
192
+ });
193
+ }
194
+ applyFastOptimizations(content) {
195
+ return content
196
+ .replace(/\s+/g, ' ') // Normalize whitespace
197
+ .replace(/>\s+</g, '><') // Remove spaces between tags
198
+ .trim();
199
+ }
200
+ applyBalancedOptimizations(content) {
201
+ let optimized = this.applyFastOptimizations(content);
202
+ // Remove unnecessary attributes
203
+ optimized = optimized
204
+ .replace(/\s+id="[^"]*"/g, '') // Remove IDs (usually not needed in components)
205
+ .replace(/\s+class="[^"]*"/g, '') // Remove classes
206
+ .replace(/<!--[\s\S]*?-->/g, '') // Remove comments
207
+ .replace(/\s+xmlns="[^"]*"/g, ''); // Remove xmlns (React adds it)
208
+ return optimized;
209
+ }
210
+ applyMaximumOptimizations(content) {
211
+ let optimized = this.applyBalancedOptimizations(content);
212
+ // Advanced optimizations
213
+ optimized = optimized
214
+ .replace(/\s+style="[^"]*"/g, '') // Remove inline styles
215
+ .replace(/\s+data-[^=]*="[^"]*"/g, '') // Remove data attributes
216
+ .replace(/fill="none"/g, '') // Remove default fill
217
+ .replace(/stroke="none"/g, '') // Remove default stroke
218
+ .replace(/\s+version="[^"]*"/g, '') // Remove version
219
+ .replace(/\s+baseProfile="[^"]*"/g, ''); // Remove baseProfile
220
+ return optimized;
221
+ }
222
+ }
223
+ /**
224
+ * Semaphore for controlling concurrency
225
+ */
226
+ class Semaphore {
227
+ permits;
228
+ waitQueue = [];
229
+ constructor(permits) {
230
+ this.permits = permits;
231
+ }
232
+ async acquire() {
233
+ if (this.permits > 0) {
234
+ this.permits--;
235
+ return Promise.resolve();
236
+ }
237
+ return new Promise((resolve) => {
238
+ this.waitQueue.push(resolve);
239
+ });
240
+ }
241
+ release() {
242
+ this.permits++;
243
+ if (this.waitQueue.length > 0) {
244
+ const resolve = this.waitQueue.shift();
245
+ this.permits--;
246
+ resolve();
247
+ }
248
+ }
249
+ }
250
+ // Export singleton instance
251
+ export const performanceEngine = PerformanceEngine.getInstance();
@@ -0,0 +1,56 @@
1
+ import { Plugin, PluginConfig } from '../types/index.js';
2
+ /**
3
+ * Plugin management system for extending SVG processing capabilities
4
+ */
5
+ export declare class PluginManager {
6
+ private static instance;
7
+ private plugins;
8
+ private activePlugins;
9
+ private constructor();
10
+ static getInstance(): PluginManager;
11
+ /**
12
+ * Load built-in plugins
13
+ */
14
+ private loadBuiltinPlugins;
15
+ /**
16
+ * Register a new plugin
17
+ */
18
+ registerPlugin(plugin: Plugin): void;
19
+ /**
20
+ * Enable a plugin
21
+ */
22
+ enablePlugin(name: string, config?: PluginConfig): void;
23
+ /**
24
+ * Disable a plugin
25
+ */
26
+ disablePlugin(name: string): void;
27
+ /**
28
+ * Process content through all active plugins
29
+ */
30
+ processContent(content: string, pluginConfigs?: PluginConfig[]): Promise<string>;
31
+ /**
32
+ * Get list of available plugins
33
+ */
34
+ getAvailablePlugins(): Array<{
35
+ name: string;
36
+ version: string;
37
+ enabled: boolean;
38
+ }>;
39
+ /**
40
+ * Built-in SVG optimizer
41
+ */
42
+ private optimizeSVG;
43
+ /**
44
+ * Built-in color theme applier
45
+ */
46
+ private applyColorTheme;
47
+ /**
48
+ * Built-in size normalizer
49
+ */
50
+ private normalizeSizes;
51
+ /**
52
+ * Clear all plugins (useful for testing)
53
+ */
54
+ clear(): void;
55
+ }
56
+ export declare const pluginManager: PluginManager;
@@ -0,0 +1,189 @@
1
+ import { logger } from '../core/logger.js';
2
+ /**
3
+ * Plugin management system for extending SVG processing capabilities
4
+ */
5
+ export class PluginManager {
6
+ static instance;
7
+ plugins = new Map();
8
+ activePlugins = new Set();
9
+ constructor() {
10
+ this.loadBuiltinPlugins();
11
+ }
12
+ static getInstance() {
13
+ if (!PluginManager.instance) {
14
+ PluginManager.instance = new PluginManager();
15
+ }
16
+ return PluginManager.instance;
17
+ }
18
+ /**
19
+ * Load built-in plugins
20
+ */
21
+ loadBuiltinPlugins() {
22
+ // SVG Optimizer Plugin
23
+ this.registerPlugin({
24
+ name: 'svg-optimizer',
25
+ version: '1.0.0',
26
+ process: async (content, options) => {
27
+ return this.optimizeSVG(content, options);
28
+ },
29
+ validate: (options) => true
30
+ });
31
+ // Color Theme Plugin
32
+ this.registerPlugin({
33
+ name: 'color-theme',
34
+ version: '1.0.0',
35
+ process: async (content, options) => {
36
+ return this.applyColorTheme(content, options);
37
+ },
38
+ validate: (options) => {
39
+ return options && typeof options.theme === 'object';
40
+ }
41
+ });
42
+ // Size Normalizer Plugin
43
+ this.registerPlugin({
44
+ name: 'size-normalizer',
45
+ version: '1.0.0',
46
+ process: async (content, options) => {
47
+ return this.normalizeSizes(content, options);
48
+ }
49
+ });
50
+ logger.debug('Built-in plugins loaded');
51
+ }
52
+ /**
53
+ * Register a new plugin
54
+ */
55
+ registerPlugin(plugin) {
56
+ if (this.plugins.has(plugin.name)) {
57
+ logger.warn(`Plugin ${plugin.name} is already registered, overwriting`);
58
+ }
59
+ this.plugins.set(plugin.name, plugin);
60
+ logger.debug(`Plugin registered: ${plugin.name} v${plugin.version}`);
61
+ }
62
+ /**
63
+ * Enable a plugin
64
+ */
65
+ enablePlugin(name, config) {
66
+ const plugin = this.plugins.get(name);
67
+ if (!plugin) {
68
+ throw new Error(`Plugin not found: ${name}`);
69
+ }
70
+ if (plugin.validate && config?.options && !plugin.validate(config.options)) {
71
+ throw new Error(`Invalid options for plugin: ${name}`);
72
+ }
73
+ this.activePlugins.add(name);
74
+ logger.info(`Plugin enabled: ${name}`);
75
+ }
76
+ /**
77
+ * Disable a plugin
78
+ */
79
+ disablePlugin(name) {
80
+ this.activePlugins.delete(name);
81
+ logger.info(`Plugin disabled: ${name}`);
82
+ }
83
+ /**
84
+ * Process content through all active plugins
85
+ */
86
+ async processContent(content, pluginConfigs = []) {
87
+ let processedContent = content;
88
+ for (const config of pluginConfigs) {
89
+ const plugin = this.plugins.get(config.name);
90
+ if (!plugin) {
91
+ logger.warn(`Plugin not found: ${config.name}, skipping`);
92
+ continue;
93
+ }
94
+ if (!this.activePlugins.has(config.name)) {
95
+ logger.debug(`Plugin ${config.name} is disabled, skipping`);
96
+ continue;
97
+ }
98
+ try {
99
+ logger.debug(`Processing with plugin: ${config.name}`);
100
+ processedContent = await plugin.process(processedContent, config.options);
101
+ }
102
+ catch (error) {
103
+ logger.error(`Plugin ${config.name} failed:`, error);
104
+ // Continue processing with other plugins
105
+ }
106
+ }
107
+ return processedContent;
108
+ }
109
+ /**
110
+ * Get list of available plugins
111
+ */
112
+ getAvailablePlugins() {
113
+ return Array.from(this.plugins.entries()).map(([name, plugin]) => ({
114
+ name,
115
+ version: plugin.version,
116
+ enabled: this.activePlugins.has(name)
117
+ }));
118
+ }
119
+ /**
120
+ * Built-in SVG optimizer
121
+ */
122
+ optimizeSVG(content, options = {}) {
123
+ let optimized = content;
124
+ // Remove unnecessary whitespace
125
+ if (options.removeWhitespace !== false) {
126
+ optimized = optimized.replace(/>\s+</g, '><');
127
+ }
128
+ // Remove empty groups
129
+ if (options.removeEmptyGroups !== false) {
130
+ optimized = optimized.replace(/<g[^>]*>\s*<\/g>/g, '');
131
+ }
132
+ // Merge similar paths (basic implementation)
133
+ if (options.mergePaths === true) {
134
+ // This would require more sophisticated path parsing
135
+ logger.debug('Path merging not implemented yet');
136
+ }
137
+ // Remove comments
138
+ if (options.removeComments !== false) {
139
+ optimized = optimized.replace(/<!--[\s\S]*?-->/g, '');
140
+ }
141
+ return optimized;
142
+ }
143
+ /**
144
+ * Built-in color theme applier
145
+ */
146
+ applyColorTheme(content, options = {}) {
147
+ if (!options.theme) {
148
+ return content;
149
+ }
150
+ let themed = content;
151
+ const theme = options.theme;
152
+ // Replace colors according to theme
153
+ for (const [originalColor, newColor] of Object.entries(theme)) {
154
+ const colorRegex = new RegExp(`(fill|stroke)=["']${originalColor}["']`, 'g');
155
+ themed = themed.replace(colorRegex, `$1="${newColor}"`);
156
+ }
157
+ return themed;
158
+ }
159
+ /**
160
+ * Built-in size normalizer
161
+ */
162
+ normalizeSizes(content, options = {}) {
163
+ const targetSize = options.size || 24;
164
+ // This is a basic implementation - would need more sophisticated sizing logic
165
+ let normalized = content;
166
+ // Normalize stroke-width relative to size
167
+ if (options.normalizeStrokes !== false) {
168
+ const strokeRegex = /stroke-width=["']([^"']+)["']/g;
169
+ normalized = normalized.replace(strokeRegex, (match, width) => {
170
+ const numericWidth = parseFloat(width);
171
+ if (!isNaN(numericWidth)) {
172
+ const normalizedWidth = (numericWidth / 24) * targetSize;
173
+ return `stroke-width="${normalizedWidth}"`;
174
+ }
175
+ return match;
176
+ });
177
+ }
178
+ return normalized;
179
+ }
180
+ /**
181
+ * Clear all plugins (useful for testing)
182
+ */
183
+ clear() {
184
+ this.plugins.clear();
185
+ this.activePlugins.clear();
186
+ }
187
+ }
188
+ // Export singleton instance
189
+ export const pluginManager = PluginManager.getInstance();