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,209 @@
1
+ import path from 'path';
2
+ import { FileSystem } from '../utils/native.js';
3
+ import { logger } from '../core/logger.js';
4
+ /**
5
+ * Professional configuration management service
6
+ */
7
+ export class ConfigService {
8
+ static instance;
9
+ static CONFIG_FILE = '.svgconfig.json';
10
+ cachedConfig = null;
11
+ constructor() { }
12
+ static getInstance() {
13
+ if (!ConfigService.instance) {
14
+ ConfigService.instance = new ConfigService();
15
+ }
16
+ return ConfigService.instance;
17
+ }
18
+ /**
19
+ * Get the default configuration
20
+ */
21
+ getDefaultConfig() {
22
+ return {
23
+ source: './src/assets/svg',
24
+ output: './src/components/icons',
25
+ framework: 'react',
26
+ typescript: true,
27
+ watch: false,
28
+ defaultWidth: 24,
29
+ defaultHeight: 24,
30
+ defaultFill: 'currentColor',
31
+ exclude: [],
32
+ styleRules: {
33
+ fill: 'inherit',
34
+ stroke: 'none',
35
+ },
36
+ plugins: [],
37
+ template: {
38
+ type: 'default'
39
+ },
40
+ frameworkOptions: {
41
+ forwardRef: true,
42
+ memo: false,
43
+ scriptSetup: true,
44
+ standalone: true
45
+ },
46
+ errorHandling: {
47
+ skipOnError: false,
48
+ logLevel: 'info',
49
+ maxRetries: 3
50
+ },
51
+ performance: {
52
+ batchSize: 10,
53
+ parallel: true,
54
+ timeout: 30000,
55
+ enableCache: true
56
+ }
57
+ };
58
+ }
59
+ /**
60
+ * Get configuration file path
61
+ */
62
+ getConfigPath() {
63
+ return path.resolve(ConfigService.CONFIG_FILE);
64
+ }
65
+ /**
66
+ * Read configuration from file with caching
67
+ */
68
+ readConfig() {
69
+ if (this.cachedConfig) {
70
+ return { ...this.cachedConfig };
71
+ }
72
+ try {
73
+ const configData = FileSystem.readJSONSync(this.getConfigPath());
74
+ if (Object.keys(configData).length === 0) {
75
+ logger.debug('No configuration found, using defaults');
76
+ this.cachedConfig = this.getDefaultConfig();
77
+ return this.cachedConfig;
78
+ }
79
+ // Merge with defaults to ensure all required properties exist
80
+ this.cachedConfig = {
81
+ ...this.getDefaultConfig(),
82
+ ...configData
83
+ };
84
+ logger.debug('Configuration loaded successfully');
85
+ return this.cachedConfig;
86
+ }
87
+ catch (error) {
88
+ logger.warn('Failed to read configuration, using defaults:', error);
89
+ this.cachedConfig = this.getDefaultConfig();
90
+ return this.cachedConfig;
91
+ }
92
+ }
93
+ /**
94
+ * Write configuration to file
95
+ */
96
+ writeConfig(config) {
97
+ try {
98
+ FileSystem.writeJSONSync(this.getConfigPath(), config, { spaces: 2 });
99
+ this.cachedConfig = config; // Update cache
100
+ logger.success('Configuration saved successfully');
101
+ }
102
+ catch (error) {
103
+ logger.error('Failed to write configuration:', error);
104
+ throw error;
105
+ }
106
+ }
107
+ /**
108
+ * Initialize configuration with defaults
109
+ */
110
+ async initConfig() {
111
+ const configPath = this.getConfigPath();
112
+ if (await FileSystem.exists(configPath)) {
113
+ logger.warn('Config file already exists:', configPath);
114
+ return;
115
+ }
116
+ const defaultConfig = this.getDefaultConfig();
117
+ this.writeConfig(defaultConfig);
118
+ logger.success('Configuration initialized with defaults');
119
+ }
120
+ /**
121
+ * Set a specific configuration value
122
+ */
123
+ setConfig(key, value) {
124
+ const config = this.readConfig();
125
+ // Support nested key paths like 'styleRules.fill'
126
+ const keys = key.split('.');
127
+ let current = config;
128
+ for (let i = 0; i < keys.length - 1; i++) {
129
+ const k = keys[i];
130
+ if (!(k in current)) {
131
+ current[k] = {};
132
+ }
133
+ current = current[k];
134
+ }
135
+ const finalKey = keys[keys.length - 1];
136
+ current[finalKey] = value;
137
+ this.writeConfig(config);
138
+ logger.success(`Configuration updated: ${key} = ${value}`);
139
+ }
140
+ /**
141
+ * Get a specific configuration value
142
+ */
143
+ getConfig(key) {
144
+ const config = this.readConfig();
145
+ if (!key) {
146
+ return config;
147
+ }
148
+ // Support nested key paths
149
+ const keys = key.split('.');
150
+ let current = config;
151
+ for (const k of keys) {
152
+ if (!(k in current)) {
153
+ return undefined;
154
+ }
155
+ current = current[k];
156
+ }
157
+ return current;
158
+ }
159
+ /**
160
+ * Validate configuration
161
+ */
162
+ validateConfig(config) {
163
+ const configToValidate = config || this.readConfig();
164
+ const errors = [];
165
+ // Required string fields
166
+ const requiredStringFields = ['source', 'output', 'defaultFill'];
167
+ for (const field of requiredStringFields) {
168
+ if (!configToValidate[field] || typeof configToValidate[field] !== 'string') {
169
+ errors.push(`${field} must be a non-empty string`);
170
+ }
171
+ }
172
+ // Required numeric fields
173
+ const requiredNumericFields = ['defaultWidth', 'defaultHeight'];
174
+ for (const field of requiredNumericFields) {
175
+ const value = configToValidate[field];
176
+ if (typeof value !== 'number' || value <= 0) {
177
+ errors.push(`${field} must be a positive number`);
178
+ }
179
+ }
180
+ // Validate exclude array
181
+ if (configToValidate.exclude && !Array.isArray(configToValidate.exclude)) {
182
+ errors.push('exclude must be an array');
183
+ }
184
+ // Validate styleRules object
185
+ if (configToValidate.styleRules && typeof configToValidate.styleRules !== 'object') {
186
+ errors.push('styleRules must be an object');
187
+ }
188
+ return {
189
+ valid: errors.length === 0,
190
+ errors
191
+ };
192
+ }
193
+ /**
194
+ * Clear cached configuration (useful for testing)
195
+ */
196
+ clearCache() {
197
+ this.cachedConfig = null;
198
+ }
199
+ /**
200
+ * Display current configuration
201
+ */
202
+ showConfig() {
203
+ const config = this.readConfig();
204
+ console.log('📄 Current Configuration:');
205
+ console.log(JSON.stringify(config, null, 2));
206
+ }
207
+ }
208
+ // Export singleton instance
209
+ export const configService = ConfigService.getInstance();
@@ -0,0 +1,54 @@
1
+ import { FileWatchEvent, WatchOptions } from '../types/index.js';
2
+ /**
3
+ * Professional file watching service with debouncing and event filtering
4
+ */
5
+ export declare class FileWatcherService {
6
+ private static instance;
7
+ private watchers;
8
+ private eventHandlers;
9
+ private debounceTimers;
10
+ private readonly debounceDelay;
11
+ private constructor();
12
+ static getInstance(): FileWatcherService;
13
+ /**
14
+ * Start watching a directory for SVG file changes
15
+ */
16
+ watchDirectory(watchPath: string, options?: Partial<WatchOptions>): Promise<string>;
17
+ /**
18
+ * Handle file system events with debouncing
19
+ */
20
+ private handleFileEvent;
21
+ /**
22
+ * Process debounced file events
23
+ */
24
+ private processFileEvent;
25
+ /**
26
+ * Register an event handler for a specific watcher
27
+ */
28
+ onFileEvent(watchId: string, handler: (event: FileWatchEvent) => void | Promise<void>): void;
29
+ /**
30
+ * Emit event to all registered handlers
31
+ */
32
+ private emitEvent;
33
+ /**
34
+ * Stop watching a specific directory
35
+ */
36
+ stopWatching(watchId: string): void;
37
+ /**
38
+ * Stop all watchers
39
+ */
40
+ stopAllWatchers(): void;
41
+ /**
42
+ * Get active watch statistics
43
+ */
44
+ getWatchStats(): {
45
+ activeWatchers: number;
46
+ pendingEvents: number;
47
+ totalHandlers: number;
48
+ };
49
+ /**
50
+ * Cleanup on shutdown
51
+ */
52
+ shutdown(): void;
53
+ }
54
+ export declare const fileWatcher: FileWatcherService;
@@ -0,0 +1,180 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { FileSystem } from '../utils/native.js';
4
+ import { logger } from '../core/logger.js';
5
+ /**
6
+ * Professional file watching service with debouncing and event filtering
7
+ */
8
+ export class FileWatcherService {
9
+ static instance;
10
+ watchers = new Map();
11
+ eventHandlers = new Map();
12
+ debounceTimers = new Map();
13
+ debounceDelay = 300; // milliseconds
14
+ constructor() { }
15
+ static getInstance() {
16
+ if (!FileWatcherService.instance) {
17
+ FileWatcherService.instance = new FileWatcherService();
18
+ }
19
+ return FileWatcherService.instance;
20
+ }
21
+ /**
22
+ * Start watching a directory for SVG file changes
23
+ */
24
+ async watchDirectory(watchPath, options = {}) {
25
+ const resolvedPath = path.resolve(watchPath);
26
+ if (!(await FileSystem.exists(resolvedPath))) {
27
+ throw new Error(`Watch path does not exist: ${resolvedPath}`);
28
+ }
29
+ const watchId = `watch-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
30
+ try {
31
+ const watcher = fs.watch(resolvedPath, {
32
+ persistent: true,
33
+ recursive: false
34
+ }, (eventType, filename) => {
35
+ if (filename) {
36
+ this.handleFileEvent(watchId, eventType, path.join(resolvedPath, filename));
37
+ }
38
+ });
39
+ this.watchers.set(watchId, watcher);
40
+ this.eventHandlers.set(watchId, []);
41
+ logger.info(`Started watching directory: ${resolvedPath}`);
42
+ return watchId;
43
+ }
44
+ catch (error) {
45
+ logger.error(`Failed to start watching ${resolvedPath}:`, error);
46
+ throw error;
47
+ }
48
+ }
49
+ /**
50
+ * Handle file system events with debouncing
51
+ */
52
+ handleFileEvent(watchId, eventType, filePath) {
53
+ // Only process SVG files
54
+ if (!filePath.endsWith('.svg')) {
55
+ return;
56
+ }
57
+ const debounceKey = `${watchId}-${filePath}`;
58
+ // Clear existing timer
59
+ if (this.debounceTimers.has(debounceKey)) {
60
+ clearTimeout(this.debounceTimers.get(debounceKey));
61
+ }
62
+ // Set new timer
63
+ const timer = setTimeout(async () => {
64
+ this.debounceTimers.delete(debounceKey);
65
+ await this.processFileEvent(watchId, eventType, filePath);
66
+ }, this.debounceDelay);
67
+ this.debounceTimers.set(debounceKey, timer);
68
+ }
69
+ /**
70
+ * Process debounced file events
71
+ */
72
+ async processFileEvent(watchId, eventType, filePath) {
73
+ try {
74
+ const exists = await FileSystem.exists(filePath);
75
+ let actualEventType;
76
+ // Determine actual event type
77
+ if (eventType === 'rename') {
78
+ actualEventType = exists ? 'add' : 'unlink';
79
+ }
80
+ else {
81
+ actualEventType = 'change';
82
+ }
83
+ const event = {
84
+ type: actualEventType,
85
+ filePath,
86
+ timestamp: Date.now()
87
+ };
88
+ logger.debug(`File event: ${actualEventType} - ${path.basename(filePath)}`);
89
+ // Emit event to registered handlers
90
+ this.emitEvent(watchId, event);
91
+ }
92
+ catch (error) {
93
+ logger.error(`Error processing file event for ${filePath}:`, error);
94
+ }
95
+ }
96
+ /**
97
+ * Register an event handler for a specific watcher
98
+ */
99
+ onFileEvent(watchId, handler) {
100
+ const handlers = this.eventHandlers.get(watchId) || [];
101
+ handlers.push(handler);
102
+ this.eventHandlers.set(watchId, handlers);
103
+ }
104
+ /**
105
+ * Emit event to all registered handlers
106
+ */
107
+ emitEvent(watchId, event) {
108
+ const handlers = this.eventHandlers.get(watchId) || [];
109
+ for (const handler of handlers) {
110
+ try {
111
+ const result = handler(event);
112
+ // Handle async handlers
113
+ if (result && typeof result.then === 'function') {
114
+ result.catch((error) => {
115
+ logger.error(`Error in file event handler:`, error);
116
+ });
117
+ }
118
+ }
119
+ catch (error) {
120
+ logger.error(`Error in file event handler:`, error);
121
+ }
122
+ }
123
+ }
124
+ /**
125
+ * Stop watching a specific directory
126
+ */
127
+ stopWatching(watchId) {
128
+ const watcher = this.watchers.get(watchId);
129
+ if (watcher) {
130
+ watcher.close();
131
+ this.watchers.delete(watchId);
132
+ this.eventHandlers.delete(watchId);
133
+ // Clear any pending debounce timers for this watcher
134
+ for (const [key, timer] of this.debounceTimers.entries()) {
135
+ if (key.startsWith(`${watchId}-`)) {
136
+ clearTimeout(timer);
137
+ this.debounceTimers.delete(key);
138
+ }
139
+ }
140
+ logger.info(`Stopped watching: ${watchId}`);
141
+ }
142
+ }
143
+ /**
144
+ * Stop all watchers
145
+ */
146
+ stopAllWatchers() {
147
+ for (const watchId of this.watchers.keys()) {
148
+ this.stopWatching(watchId);
149
+ }
150
+ logger.info('Stopped all file watchers');
151
+ }
152
+ /**
153
+ * Get active watch statistics
154
+ */
155
+ getWatchStats() {
156
+ let totalHandlers = 0;
157
+ for (const handlers of this.eventHandlers.values()) {
158
+ totalHandlers += handlers.length;
159
+ }
160
+ return {
161
+ activeWatchers: this.watchers.size,
162
+ pendingEvents: this.debounceTimers.size,
163
+ totalHandlers
164
+ };
165
+ }
166
+ /**
167
+ * Cleanup on shutdown
168
+ */
169
+ shutdown() {
170
+ this.stopAllWatchers();
171
+ // Clear all debounce timers
172
+ for (const timer of this.debounceTimers.values()) {
173
+ clearTimeout(timer);
174
+ }
175
+ this.debounceTimers.clear();
176
+ logger.info('File watcher service shutdown complete');
177
+ }
178
+ }
179
+ // Export singleton instance
180
+ export const fileWatcher = FileWatcherService.getInstance();
@@ -0,0 +1,81 @@
1
+ import { BuildOptions, GenerateOptions, WatchOptions } from '../types/index.js';
2
+ /**
3
+ * Main SVG service that orchestrates all SVG processing operations
4
+ */
5
+ export declare class SVGService {
6
+ private static instance;
7
+ private activeWatchers;
8
+ lockService: LockService;
9
+ private constructor();
10
+ static getInstance(): SVGService;
11
+ /**
12
+ * Build all SVG files from source to output directory
13
+ */
14
+ buildAll(options: BuildOptions): Promise<void>;
15
+ /**
16
+ * Generate a React component from a single SVG file
17
+ */
18
+ generateSingle(options: GenerateOptions): Promise<void>;
19
+ /**
20
+ * Start watching SVG files for changes
21
+ */
22
+ startWatching(options: WatchOptions): Promise<string>;
23
+ /**
24
+ * Handle file watch events
25
+ */
26
+ private handleWatchEvent;
27
+ /**
28
+ * Process a watched file
29
+ */
30
+ private processWatchedFile;
31
+ /**
32
+ * Handle file removal in watch mode
33
+ */
34
+ private handleFileRemoval;
35
+ /**
36
+ * Stop watching files
37
+ */
38
+ stopWatching(watchId?: string): void;
39
+ /**
40
+ * Clean output directory
41
+ */
42
+ clean(outDir: string): Promise<void>;
43
+ /**
44
+ * Generate index.ts file with all component exports
45
+ */
46
+ private generateIndexFile;
47
+ /**
48
+ * Generate the content for index.ts file
49
+ */
50
+ private generateIndexContent;
51
+ /**
52
+ * Get service statistics
53
+ */
54
+ getStats(): {
55
+ activeWatchers: number;
56
+ processingQueue: any;
57
+ watcherStats: any;
58
+ };
59
+ /**
60
+ * Shutdown service
61
+ */
62
+ shutdown(): void;
63
+ }
64
+ /**
65
+ * Simple file locking service
66
+ */
67
+ export declare class LockService {
68
+ private static instance;
69
+ private static readonly LOCK_FILE;
70
+ private cachedLocks;
71
+ private constructor();
72
+ static getInstance(): LockService;
73
+ private getLockFilePath;
74
+ private readLockFile;
75
+ private writeLockFile;
76
+ lockFiles(files: string[]): void;
77
+ unlockFiles(files: string[]): void;
78
+ isLocked(file: string): boolean;
79
+ clearCache(): void;
80
+ }
81
+ export declare const svgService: SVGService;