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,383 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { FileSystem } from '../utils/native.js';
|
|
3
|
+
import { logger } from '../core/logger.js';
|
|
4
|
+
import { configService } from './config.js';
|
|
5
|
+
import { svgProcessor } from '../processors/svg-processor.js';
|
|
6
|
+
import { fileWatcher } from './file-watcher.js';
|
|
7
|
+
/**
|
|
8
|
+
* Main SVG service that orchestrates all SVG processing operations
|
|
9
|
+
*/
|
|
10
|
+
export class SVGService {
|
|
11
|
+
static instance;
|
|
12
|
+
activeWatchers = new Set();
|
|
13
|
+
lockService;
|
|
14
|
+
constructor() {
|
|
15
|
+
this.lockService = LockService.getInstance();
|
|
16
|
+
}
|
|
17
|
+
static getInstance() {
|
|
18
|
+
if (!SVGService.instance) {
|
|
19
|
+
SVGService.instance = new SVGService();
|
|
20
|
+
}
|
|
21
|
+
return SVGService.instance;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Build all SVG files from source to output directory
|
|
25
|
+
*/
|
|
26
|
+
async buildAll(options) {
|
|
27
|
+
logger.info('Starting SVG build process');
|
|
28
|
+
logger.info(`Source: ${options.src}`);
|
|
29
|
+
logger.info(`Output: ${options.out}`);
|
|
30
|
+
const srcDir = path.resolve(options.src);
|
|
31
|
+
const outDir = path.resolve(options.out);
|
|
32
|
+
// Validate source directory
|
|
33
|
+
if (!(await FileSystem.exists(srcDir))) {
|
|
34
|
+
throw new Error(`Source folder not found: ${srcDir}`);
|
|
35
|
+
}
|
|
36
|
+
// Ensure output directory exists
|
|
37
|
+
await FileSystem.ensureDir(outDir);
|
|
38
|
+
// Get configuration - merge config file with options
|
|
39
|
+
const config = configService.readConfig();
|
|
40
|
+
const mergedConfig = {
|
|
41
|
+
...config,
|
|
42
|
+
...(options.config || {}),
|
|
43
|
+
// Support direct properties on options for CLI convenience
|
|
44
|
+
...options.framework && { framework: options.framework },
|
|
45
|
+
...options.typescript !== undefined && { typescript: options.typescript },
|
|
46
|
+
...options.frameworkOptions && { frameworkOptions: options.frameworkOptions }
|
|
47
|
+
};
|
|
48
|
+
// Read all SVG files
|
|
49
|
+
const files = await FileSystem.readDir(srcDir);
|
|
50
|
+
const svgFiles = files.filter((file) => file.endsWith('.svg'));
|
|
51
|
+
if (svgFiles.length === 0) {
|
|
52
|
+
logger.warn('No SVG files found in source directory');
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
logger.info(`Found ${svgFiles.length} SVG files to process`);
|
|
56
|
+
const results = [];
|
|
57
|
+
// Process each SVG file
|
|
58
|
+
for (const file of svgFiles) {
|
|
59
|
+
const svgPath = path.join(srcDir, file);
|
|
60
|
+
// Check if file is locked
|
|
61
|
+
if (this.lockService.isLocked(svgPath)) {
|
|
62
|
+
logger.warn(`Skipped locked file: ${file}`);
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
const processingResult = await svgProcessor.processSVGFile(svgPath, outDir, {
|
|
67
|
+
framework: mergedConfig.framework,
|
|
68
|
+
typescript: mergedConfig.typescript,
|
|
69
|
+
frameworkOptions: mergedConfig.frameworkOptions,
|
|
70
|
+
defaultWidth: mergedConfig.defaultWidth,
|
|
71
|
+
defaultHeight: mergedConfig.defaultHeight,
|
|
72
|
+
defaultFill: mergedConfig.defaultFill,
|
|
73
|
+
styleRules: Object.fromEntries(Object.entries(mergedConfig.styleRules || {}).filter(([_, v]) => v !== undefined))
|
|
74
|
+
});
|
|
75
|
+
results.push({
|
|
76
|
+
success: processingResult.success,
|
|
77
|
+
file,
|
|
78
|
+
error: processingResult.error
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
logger.error(`Failed to process ${file}:`, error);
|
|
83
|
+
results.push({
|
|
84
|
+
success: false,
|
|
85
|
+
file,
|
|
86
|
+
error: error
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Log summary
|
|
91
|
+
const successful = results.filter(r => r.success).length;
|
|
92
|
+
const failed = results.filter(r => !r.success).length;
|
|
93
|
+
logger.info(`Build complete: ${successful} successful, ${failed} failed`);
|
|
94
|
+
if (failed > 0) {
|
|
95
|
+
logger.warn('Some files failed to process:');
|
|
96
|
+
results.filter(r => !r.success).forEach(r => {
|
|
97
|
+
logger.warn(` - ${r.file}: ${r.error?.message}`);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
// Generate index.ts file with all component exports
|
|
101
|
+
if (successful > 0) {
|
|
102
|
+
await this.generateIndexFile(outDir, results.filter(r => r.success).map(r => r.file));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Generate a React component from a single SVG file
|
|
107
|
+
*/
|
|
108
|
+
async generateSingle(options) {
|
|
109
|
+
logger.info(`Generating component from: ${options.svgFile}`);
|
|
110
|
+
const filePath = path.resolve(options.svgFile);
|
|
111
|
+
const outDir = path.resolve(options.outDir);
|
|
112
|
+
// Validate SVG file
|
|
113
|
+
if (!(await FileSystem.exists(filePath))) {
|
|
114
|
+
throw new Error(`SVG file not found: ${filePath}`);
|
|
115
|
+
}
|
|
116
|
+
// Check if file is locked
|
|
117
|
+
if (this.lockService.isLocked(filePath)) {
|
|
118
|
+
logger.warn(`File is locked: ${path.basename(options.svgFile)}`);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
// Get configuration
|
|
122
|
+
const config = configService.readConfig();
|
|
123
|
+
const mergedConfig = { ...config, ...options.config };
|
|
124
|
+
// Process the file
|
|
125
|
+
const result = await svgProcessor.processSVGFile(filePath, outDir, {
|
|
126
|
+
defaultWidth: mergedConfig.defaultWidth,
|
|
127
|
+
defaultHeight: mergedConfig.defaultHeight,
|
|
128
|
+
defaultFill: mergedConfig.defaultFill,
|
|
129
|
+
styleRules: Object.fromEntries(Object.entries(mergedConfig.styleRules || {}).filter(([_, v]) => v !== undefined))
|
|
130
|
+
});
|
|
131
|
+
if (!result.success) {
|
|
132
|
+
throw result.error || new Error('Failed to generate component');
|
|
133
|
+
}
|
|
134
|
+
logger.success(`Component generated: ${result.componentName}`);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Start watching SVG files for changes
|
|
138
|
+
*/
|
|
139
|
+
async startWatching(options) {
|
|
140
|
+
logger.info('Starting watch mode');
|
|
141
|
+
logger.info(`Watching: ${options.src}`);
|
|
142
|
+
logger.info(`Output: ${options.out}`);
|
|
143
|
+
const srcDir = path.resolve(options.src);
|
|
144
|
+
const outDir = path.resolve(options.out);
|
|
145
|
+
// Validate source directory
|
|
146
|
+
if (!(await FileSystem.exists(srcDir))) {
|
|
147
|
+
throw new Error(`Source folder not found: ${srcDir}`);
|
|
148
|
+
}
|
|
149
|
+
// Start watching
|
|
150
|
+
const watchId = await fileWatcher.watchDirectory(srcDir, options);
|
|
151
|
+
this.activeWatchers.add(watchId);
|
|
152
|
+
// Register event handler
|
|
153
|
+
fileWatcher.onFileEvent(watchId, async (event) => {
|
|
154
|
+
await this.handleWatchEvent(event, outDir, options.config);
|
|
155
|
+
});
|
|
156
|
+
logger.success(`Watch mode active - waiting for file changes...`);
|
|
157
|
+
return watchId;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Handle file watch events
|
|
161
|
+
*/
|
|
162
|
+
async handleWatchEvent(event, outDir, config) {
|
|
163
|
+
const fileName = path.basename(event.filePath);
|
|
164
|
+
switch (event.type) {
|
|
165
|
+
case 'add':
|
|
166
|
+
logger.info(`New SVG detected: ${fileName}`);
|
|
167
|
+
await this.processWatchedFile(event.filePath, outDir, config);
|
|
168
|
+
break;
|
|
169
|
+
case 'change':
|
|
170
|
+
logger.info(`SVG updated: ${fileName}`);
|
|
171
|
+
await this.processWatchedFile(event.filePath, outDir, config);
|
|
172
|
+
break;
|
|
173
|
+
case 'unlink':
|
|
174
|
+
logger.info(`SVG removed: ${fileName}`);
|
|
175
|
+
await this.handleFileRemoval(event.filePath, outDir);
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Process a watched file
|
|
181
|
+
*/
|
|
182
|
+
async processWatchedFile(filePath, outDir, config) {
|
|
183
|
+
try {
|
|
184
|
+
// Check if file is locked
|
|
185
|
+
if (this.lockService.isLocked(filePath)) {
|
|
186
|
+
logger.warn(`Skipped locked file: ${path.basename(filePath)}`);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
// Get configuration
|
|
190
|
+
const fullConfig = configService.readConfig();
|
|
191
|
+
const mergedConfig = { ...fullConfig, ...config };
|
|
192
|
+
// Process the file
|
|
193
|
+
await svgProcessor.processSVGFile(filePath, outDir, {
|
|
194
|
+
defaultWidth: mergedConfig.defaultWidth,
|
|
195
|
+
defaultHeight: mergedConfig.defaultHeight,
|
|
196
|
+
defaultFill: mergedConfig.defaultFill,
|
|
197
|
+
styleRules: Object.fromEntries(Object.entries(mergedConfig.styleRules || {}).filter(([_, v]) => v !== undefined))
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
logger.error(`Failed to process watched file ${path.basename(filePath)}:`, error);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Handle file removal in watch mode
|
|
206
|
+
*/
|
|
207
|
+
async handleFileRemoval(filePath, outDir) {
|
|
208
|
+
try {
|
|
209
|
+
const componentName = svgProcessor.generateComponentName(path.basename(filePath));
|
|
210
|
+
const componentPath = path.join(outDir, `${componentName}.tsx`);
|
|
211
|
+
if (await FileSystem.exists(componentPath)) {
|
|
212
|
+
await FileSystem.unlink(componentPath);
|
|
213
|
+
logger.success(`Removed component: ${componentName}.tsx`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
logger.error(`Failed to remove component for ${path.basename(filePath)}:`, error);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Stop watching files
|
|
222
|
+
*/
|
|
223
|
+
stopWatching(watchId) {
|
|
224
|
+
if (watchId) {
|
|
225
|
+
fileWatcher.stopWatching(watchId);
|
|
226
|
+
this.activeWatchers.delete(watchId);
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
// Stop all watchers
|
|
230
|
+
for (const id of this.activeWatchers) {
|
|
231
|
+
fileWatcher.stopWatching(id);
|
|
232
|
+
}
|
|
233
|
+
this.activeWatchers.clear();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Clean output directory
|
|
238
|
+
*/
|
|
239
|
+
async clean(outDir) {
|
|
240
|
+
const targetDir = path.resolve(outDir);
|
|
241
|
+
if (!(await FileSystem.exists(targetDir))) {
|
|
242
|
+
logger.warn(`Directory not found: ${targetDir}`);
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
await FileSystem.emptyDir(targetDir);
|
|
246
|
+
logger.success(`Cleaned all generated SVG components in: ${targetDir}`);
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Generate index.ts file with all component exports
|
|
250
|
+
*/
|
|
251
|
+
async generateIndexFile(outDir, svgFiles) {
|
|
252
|
+
try {
|
|
253
|
+
const componentNames = svgFiles.map(file => {
|
|
254
|
+
const baseName = path.basename(file, '.svg');
|
|
255
|
+
return svgProcessor.generateComponentName(baseName);
|
|
256
|
+
});
|
|
257
|
+
const indexContent = this.generateIndexContent(componentNames);
|
|
258
|
+
const indexPath = path.join(outDir, 'index.ts');
|
|
259
|
+
await FileSystem.writeFile(indexPath, indexContent, 'utf-8');
|
|
260
|
+
logger.success(`Generated index.ts with ${componentNames.length} component exports`);
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
logger.error('Failed to generate index.ts:', error);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Generate the content for index.ts file
|
|
268
|
+
*/
|
|
269
|
+
generateIndexContent(componentNames) {
|
|
270
|
+
const imports = componentNames.map(name => `export { default as ${name} } from './${name}';`).join('\n');
|
|
271
|
+
const exportAll = `
|
|
272
|
+
// Export all components
|
|
273
|
+
export {
|
|
274
|
+
${componentNames.map(name => ` ${name},`).join('\n')}
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
// Re-export for convenience
|
|
278
|
+
export default {
|
|
279
|
+
${componentNames.map(name => ` ${name},`).join('\n')}
|
|
280
|
+
};
|
|
281
|
+
`;
|
|
282
|
+
return `/**
|
|
283
|
+
* SVG Components Index
|
|
284
|
+
* Generated by svger-cli
|
|
285
|
+
*
|
|
286
|
+
* Import individual components:
|
|
287
|
+
* import { ${componentNames[0] || 'ComponentName'} } from './components';
|
|
288
|
+
*
|
|
289
|
+
* Import all components:
|
|
290
|
+
* import * as Icons from './components';
|
|
291
|
+
* import Icons from './components'; // default export
|
|
292
|
+
*/
|
|
293
|
+
|
|
294
|
+
${imports}${exportAll}`;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Get service statistics
|
|
298
|
+
*/
|
|
299
|
+
getStats() {
|
|
300
|
+
return {
|
|
301
|
+
activeWatchers: this.activeWatchers.size,
|
|
302
|
+
processingQueue: svgProcessor.getProcessingStats(),
|
|
303
|
+
watcherStats: fileWatcher.getWatchStats()
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Shutdown service
|
|
308
|
+
*/
|
|
309
|
+
shutdown() {
|
|
310
|
+
this.stopWatching();
|
|
311
|
+
fileWatcher.shutdown();
|
|
312
|
+
svgProcessor.clearQueue();
|
|
313
|
+
logger.info('SVG service shutdown complete');
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Simple file locking service
|
|
318
|
+
*/
|
|
319
|
+
export class LockService {
|
|
320
|
+
static instance;
|
|
321
|
+
static LOCK_FILE = '.svg-lock';
|
|
322
|
+
cachedLocks = null;
|
|
323
|
+
constructor() { }
|
|
324
|
+
static getInstance() {
|
|
325
|
+
if (!LockService.instance) {
|
|
326
|
+
LockService.instance = new LockService();
|
|
327
|
+
}
|
|
328
|
+
return LockService.instance;
|
|
329
|
+
}
|
|
330
|
+
getLockFilePath() {
|
|
331
|
+
return path.resolve(LockService.LOCK_FILE);
|
|
332
|
+
}
|
|
333
|
+
readLockFile() {
|
|
334
|
+
if (this.cachedLocks) {
|
|
335
|
+
return this.cachedLocks;
|
|
336
|
+
}
|
|
337
|
+
try {
|
|
338
|
+
const data = FileSystem.readJSONSync(this.getLockFilePath());
|
|
339
|
+
this.cachedLocks = new Set(Array.isArray(data) ? data : []);
|
|
340
|
+
return this.cachedLocks;
|
|
341
|
+
}
|
|
342
|
+
catch {
|
|
343
|
+
this.cachedLocks = new Set();
|
|
344
|
+
return this.cachedLocks;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
writeLockFile(locks) {
|
|
348
|
+
try {
|
|
349
|
+
FileSystem.writeJSONSync(this.getLockFilePath(), Array.from(locks), { spaces: 2 });
|
|
350
|
+
this.cachedLocks = locks;
|
|
351
|
+
}
|
|
352
|
+
catch (error) {
|
|
353
|
+
logger.error('Failed to write lock file:', error);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
lockFiles(files) {
|
|
357
|
+
const fileNames = files.map(f => path.basename(f));
|
|
358
|
+
const current = this.readLockFile();
|
|
359
|
+
for (const fileName of fileNames) {
|
|
360
|
+
current.add(fileName);
|
|
361
|
+
}
|
|
362
|
+
this.writeLockFile(current);
|
|
363
|
+
logger.success(`Locked files: ${fileNames.join(', ')}`);
|
|
364
|
+
}
|
|
365
|
+
unlockFiles(files) {
|
|
366
|
+
const fileNames = files.map(f => path.basename(f));
|
|
367
|
+
const current = this.readLockFile();
|
|
368
|
+
for (const fileName of fileNames) {
|
|
369
|
+
current.delete(fileName);
|
|
370
|
+
}
|
|
371
|
+
this.writeLockFile(current);
|
|
372
|
+
logger.success(`Unlocked files: ${fileNames.join(', ')}`);
|
|
373
|
+
}
|
|
374
|
+
isLocked(file) {
|
|
375
|
+
const locks = this.readLockFile();
|
|
376
|
+
return locks.has(path.basename(file));
|
|
377
|
+
}
|
|
378
|
+
clearCache() {
|
|
379
|
+
this.cachedLocks = null;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
// Export singleton instance
|
|
383
|
+
export const svgService = SVGService.getInstance();
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for svger-cli
|
|
3
|
+
*/
|
|
4
|
+
export type FrameworkType = 'react' | 'vue' | 'svelte' | 'angular' | 'solid' | 'preact' | 'lit' | 'vanilla';
|
|
5
|
+
export interface SVGConfig {
|
|
6
|
+
source: string;
|
|
7
|
+
output: string;
|
|
8
|
+
watch: boolean;
|
|
9
|
+
framework: FrameworkType;
|
|
10
|
+
typescript: boolean;
|
|
11
|
+
defaultWidth: number;
|
|
12
|
+
defaultHeight: number;
|
|
13
|
+
defaultFill: string;
|
|
14
|
+
exclude: string[];
|
|
15
|
+
styleRules: {
|
|
16
|
+
fill?: string;
|
|
17
|
+
stroke?: string;
|
|
18
|
+
[key: string]: string | undefined;
|
|
19
|
+
};
|
|
20
|
+
plugins?: PluginConfig[];
|
|
21
|
+
template?: TemplateConfig;
|
|
22
|
+
frameworkOptions?: FrameworkOptions;
|
|
23
|
+
errorHandling?: {
|
|
24
|
+
skipOnError: boolean;
|
|
25
|
+
logLevel: 'debug' | 'info' | 'warn' | 'error';
|
|
26
|
+
maxRetries: number;
|
|
27
|
+
};
|
|
28
|
+
performance?: {
|
|
29
|
+
batchSize: number;
|
|
30
|
+
parallel: boolean;
|
|
31
|
+
timeout: number;
|
|
32
|
+
enableCache: boolean;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export interface FrameworkOptions {
|
|
36
|
+
composition?: boolean;
|
|
37
|
+
setup?: boolean;
|
|
38
|
+
scriptSetup?: boolean;
|
|
39
|
+
standalone?: boolean;
|
|
40
|
+
moduleImport?: boolean;
|
|
41
|
+
signals?: boolean;
|
|
42
|
+
forwardRef?: boolean;
|
|
43
|
+
memo?: boolean;
|
|
44
|
+
customElement?: boolean;
|
|
45
|
+
shadowDom?: boolean;
|
|
46
|
+
cssModules?: boolean;
|
|
47
|
+
styledComponents?: boolean;
|
|
48
|
+
}
|
|
49
|
+
export interface BuildOptions {
|
|
50
|
+
src: string;
|
|
51
|
+
out: string;
|
|
52
|
+
config?: Partial<SVGConfig>;
|
|
53
|
+
}
|
|
54
|
+
export interface GenerateOptions {
|
|
55
|
+
svgFile: string;
|
|
56
|
+
outDir: string;
|
|
57
|
+
config?: Partial<SVGConfig>;
|
|
58
|
+
}
|
|
59
|
+
export interface WatchOptions {
|
|
60
|
+
src: string;
|
|
61
|
+
out: string;
|
|
62
|
+
config?: Partial<SVGConfig>;
|
|
63
|
+
}
|
|
64
|
+
export interface ComponentGenerationOptions {
|
|
65
|
+
componentName: string;
|
|
66
|
+
svgContent: string;
|
|
67
|
+
framework: FrameworkType;
|
|
68
|
+
typescript: boolean;
|
|
69
|
+
defaultWidth?: number;
|
|
70
|
+
defaultHeight?: number;
|
|
71
|
+
defaultFill?: string;
|
|
72
|
+
styleRules?: Record<string, string>;
|
|
73
|
+
template?: TemplateConfig;
|
|
74
|
+
frameworkOptions?: FrameworkOptions;
|
|
75
|
+
}
|
|
76
|
+
export interface TemplateConfig {
|
|
77
|
+
type: 'default' | 'custom';
|
|
78
|
+
path?: string;
|
|
79
|
+
options?: Record<string, any>;
|
|
80
|
+
}
|
|
81
|
+
export interface PluginConfig {
|
|
82
|
+
name: string;
|
|
83
|
+
options?: Record<string, any>;
|
|
84
|
+
}
|
|
85
|
+
export interface SVGProcessorResult {
|
|
86
|
+
success: boolean;
|
|
87
|
+
componentName: string;
|
|
88
|
+
filePath: string;
|
|
89
|
+
error?: Error;
|
|
90
|
+
}
|
|
91
|
+
export interface FileWatchEvent {
|
|
92
|
+
type: 'add' | 'change' | 'unlink';
|
|
93
|
+
filePath: string;
|
|
94
|
+
timestamp: number;
|
|
95
|
+
}
|
|
96
|
+
export interface ProcessingContext {
|
|
97
|
+
config: SVGConfig;
|
|
98
|
+
sourceDir: string;
|
|
99
|
+
outputDir: string;
|
|
100
|
+
fileQueue: string[];
|
|
101
|
+
locks: Set<string>;
|
|
102
|
+
cache?: Map<string, CachedComponent>;
|
|
103
|
+
}
|
|
104
|
+
export interface CachedComponent {
|
|
105
|
+
hash: string;
|
|
106
|
+
componentName: string;
|
|
107
|
+
filePath: string;
|
|
108
|
+
framework: FrameworkType;
|
|
109
|
+
timestamp: number;
|
|
110
|
+
svgHash: string;
|
|
111
|
+
}
|
|
112
|
+
export interface Logger {
|
|
113
|
+
info(message: string, ...args: any[]): void;
|
|
114
|
+
warn(message: string, ...args: any[]): void;
|
|
115
|
+
error(message: string, ...args: any[]): void;
|
|
116
|
+
success(message: string, ...args: any[]): void;
|
|
117
|
+
debug(message: string, ...args: any[]): void;
|
|
118
|
+
}
|
|
119
|
+
export interface Plugin {
|
|
120
|
+
name: string;
|
|
121
|
+
version: string;
|
|
122
|
+
process(content: string, options?: any): Promise<string>;
|
|
123
|
+
validate?(options?: any): boolean;
|
|
124
|
+
}
|
|
125
|
+
export interface Template {
|
|
126
|
+
name: string;
|
|
127
|
+
generate(options: ComponentGenerationOptions): string;
|
|
128
|
+
validate?(options: ComponentGenerationOptions): boolean;
|
|
129
|
+
}
|
|
130
|
+
export type FileSystemEvent = 'change' | 'rename';
|
|
131
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
132
|
+
export type ProcessingStatus = 'pending' | 'processing' | 'completed' | 'failed';
|
|
133
|
+
export interface ProcessingJob {
|
|
134
|
+
id: string;
|
|
135
|
+
filePath: string;
|
|
136
|
+
status: ProcessingStatus;
|
|
137
|
+
startTime: number;
|
|
138
|
+
endTime?: number;
|
|
139
|
+
error?: Error;
|
|
140
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native Node.js utilities to replace external dependencies
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Convert string to PascalCase (replaces change-case package)
|
|
6
|
+
*/
|
|
7
|
+
export declare function toPascalCase(str: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Native file system utilities (replaces fs-extra package)
|
|
10
|
+
*/
|
|
11
|
+
export declare class FileSystem {
|
|
12
|
+
private static _readFile;
|
|
13
|
+
private static _writeFile;
|
|
14
|
+
private static _readdir;
|
|
15
|
+
private static _stat;
|
|
16
|
+
private static _mkdir;
|
|
17
|
+
private static _rmdir;
|
|
18
|
+
private static _unlink;
|
|
19
|
+
static exists(path: string): Promise<boolean>;
|
|
20
|
+
static readFile(path: string, encoding?: BufferEncoding): Promise<string>;
|
|
21
|
+
static writeFile(path: string, content: string, encoding?: BufferEncoding): Promise<void>;
|
|
22
|
+
static readDir(path: string): Promise<string[]>;
|
|
23
|
+
static ensureDir(dirPath: string): Promise<void>;
|
|
24
|
+
static removeDir(dirPath: string): Promise<void>;
|
|
25
|
+
static emptyDir(dirPath: string): Promise<void>;
|
|
26
|
+
static unlink(filePath: string): Promise<void>;
|
|
27
|
+
static readJSONSync(path: string): any;
|
|
28
|
+
static writeJSONSync(path: string, data: any, options?: {
|
|
29
|
+
spaces?: number;
|
|
30
|
+
}): void;
|
|
31
|
+
static existsSync(path: string): boolean;
|
|
32
|
+
static ensureDirSync(dirPath: string): void;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Simple CLI argument parser (replaces commander package)
|
|
36
|
+
*/
|
|
37
|
+
export declare class CLI {
|
|
38
|
+
private commands;
|
|
39
|
+
private programName;
|
|
40
|
+
private programDescription;
|
|
41
|
+
private programVersion;
|
|
42
|
+
name(name: string): this;
|
|
43
|
+
description(desc: string): this;
|
|
44
|
+
version(version: string): this;
|
|
45
|
+
command(signature: string): CommandBuilder;
|
|
46
|
+
addCommand(signature: string, description: string, action: Function, options: Map<string, any>): void;
|
|
47
|
+
parse(): Promise<void>;
|
|
48
|
+
private parseArgs;
|
|
49
|
+
private showHelp;
|
|
50
|
+
}
|
|
51
|
+
declare class CommandBuilder {
|
|
52
|
+
private signature;
|
|
53
|
+
private desc;
|
|
54
|
+
private cli;
|
|
55
|
+
private options;
|
|
56
|
+
constructor(signature: string, cli: CLI);
|
|
57
|
+
description(desc: string): this;
|
|
58
|
+
option(flag: string, description: string): this;
|
|
59
|
+
action(fn: Function): void;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* File watcher using native fs.watch (replaces chokidar)
|
|
63
|
+
*/
|
|
64
|
+
export declare class FileWatcher {
|
|
65
|
+
private watchers;
|
|
66
|
+
private callbacks;
|
|
67
|
+
watch(path: string, options?: {
|
|
68
|
+
recursive?: boolean;
|
|
69
|
+
}): this;
|
|
70
|
+
on(event: string, callback: Function): this;
|
|
71
|
+
private emit;
|
|
72
|
+
close(): void;
|
|
73
|
+
}
|
|
74
|
+
export {};
|