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.
- package/dist/cli.js +0 -0
- package/dist/core/error-handler.d.ts +63 -0
- package/dist/core/error-handler.js +224 -0
- package/dist/core/framework-templates.d.ts +17 -0
- package/{src/core/framework-templates.ts → dist/core/framework-templates.js} +100 -137
- package/dist/core/logger.d.ts +22 -0
- package/dist/core/logger.js +85 -0
- package/dist/core/performance-engine.d.ts +67 -0
- package/dist/core/performance-engine.js +251 -0
- package/dist/core/plugin-manager.d.ts +56 -0
- package/dist/core/plugin-manager.js +189 -0
- package/dist/core/style-compiler.d.ts +88 -0
- package/dist/core/style-compiler.js +466 -0
- package/dist/core/template-manager.d.ts +64 -0
- package/{src/core/template-manager.ts → dist/core/template-manager.js} +172 -255
- package/dist/index.d.ts +151 -0
- package/{src/index.ts → dist/index.js} +30 -108
- package/dist/processors/svg-processor.d.ts +67 -0
- package/dist/processors/svg-processor.js +225 -0
- package/dist/services/config.d.ts +55 -0
- package/dist/services/config.js +209 -0
- package/dist/services/file-watcher.d.ts +54 -0
- package/dist/services/file-watcher.js +180 -0
- package/dist/services/svg-service.d.ts +81 -0
- package/dist/services/svg-service.js +383 -0
- package/dist/types/index.d.ts +140 -0
- package/dist/types/index.js +4 -0
- package/dist/utils/native.d.ts +74 -0
- package/dist/utils/native.js +305 -0
- package/package.json +9 -10
- package/.svgconfig.json +0 -3
- package/CODE_OF_CONDUCT.md +0 -79
- package/CONTRIBUTING.md +0 -146
- package/TESTING.md +0 -143
- package/cli-framework.test.js +0 -16
- package/cli-test-angular/Arrowbenddownleft.component.ts +0 -27
- package/cli-test-angular/Vite.component.ts +0 -27
- package/cli-test-angular/index.ts +0 -25
- package/cli-test-output/Arrowbenddownleft.vue +0 -33
- package/cli-test-output/Vite.vue +0 -33
- package/cli-test-output/index.ts +0 -25
- package/cli-test-react/Arrowbenddownleft.tsx +0 -39
- package/cli-test-react/Vite.tsx +0 -39
- package/cli-test-react/index.ts +0 -25
- package/cli-test-svelte/Arrowbenddownleft.svelte +0 -22
- package/cli-test-svelte/Vite.svelte +0 -22
- package/cli-test-svelte/index.ts +0 -25
- package/docs/ADR-SVG-INTRGRATION-METHODS-001.adr.md +0 -157
- package/docs/ADR-SVG-INTRGRATION-METHODS-002.adr.md +0 -550
- package/docs/FRAMEWORK-GUIDE.md +0 -768
- package/docs/IMPLEMENTATION-SUMMARY.md +0 -376
- package/docs/TDR-SVG-INTRGRATION-METHODS-001.tdr.md +0 -115
- package/frameworks.test.js +0 -170
- package/my-svgs/ArrowBendDownLeft.svg +0 -6
- package/my-svgs/vite.svg +0 -1
- package/src/builder.ts +0 -104
- package/src/clean.ts +0 -21
- package/src/cli.ts +0 -221
- package/src/config.ts +0 -81
- package/src/core/error-handler.ts +0 -303
- package/src/core/logger.ts +0 -104
- package/src/core/performance-engine.ts +0 -327
- package/src/core/plugin-manager.ts +0 -228
- package/src/core/style-compiler.ts +0 -605
- package/src/lock.ts +0 -74
- package/src/processors/svg-processor.ts +0 -288
- package/src/services/config.ts +0 -241
- package/src/services/file-watcher.ts +0 -218
- package/src/services/svg-service.ts +0 -468
- package/src/templates/ComponentTemplate.ts +0 -57
- package/src/types/index.ts +0 -169
- package/src/utils/native.ts +0 -352
- package/src/watch.ts +0 -88
- package/test-output-mulit/TestIcon-angular-module.component.ts +0 -26
- package/test-output-mulit/TestIcon-angular-standalone.component.ts +0 -27
- package/test-output-mulit/TestIcon-lit.ts +0 -35
- package/test-output-mulit/TestIcon-preact.tsx +0 -38
- package/test-output-mulit/TestIcon-react.tsx +0 -35
- package/test-output-mulit/TestIcon-solid.tsx +0 -27
- package/test-output-mulit/TestIcon-svelte.svelte +0 -22
- package/test-output-mulit/TestIcon-vanilla.ts +0 -37
- package/test-output-mulit/TestIcon-vue-composition.vue +0 -33
- package/test-output-mulit/TestIcon-vue-options.vue +0 -31
- 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;
|