svger-cli 2.0.2 → 2.0.3
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/.svgerconfig.example.json +38 -0
- package/CHANGELOG.md +64 -0
- package/DEVELOPMENT.md +353 -0
- package/README.md +24 -5
- package/SECURITY.md +69 -0
- package/dist/builder.js +16 -16
- package/dist/clean.js +2 -2
- package/dist/cli.js +38 -38
- package/dist/config.js +11 -11
- package/dist/core/error-handler.js +12 -9
- package/dist/core/framework-templates.js +5 -3
- package/dist/core/performance-engine.js +9 -8
- package/dist/core/plugin-manager.js +7 -5
- package/dist/core/style-compiler.js +17 -15
- package/dist/core/template-manager.js +14 -14
- package/dist/index.d.ts +8 -6
- package/dist/index.js +5 -5
- package/dist/lock.js +7 -7
- package/dist/processors/svg-processor.d.ts +9 -3
- package/dist/processors/svg-processor.js +53 -17
- package/dist/services/config.js +11 -9
- package/dist/services/file-watcher.js +3 -3
- package/dist/services/svg-service.js +24 -12
- package/dist/templates/ComponentTemplate.js +25 -25
- package/dist/types/index.d.ts +7 -1
- package/dist/utils/native.d.ts +31 -1
- package/dist/utils/native.js +43 -8
- package/dist/watch.d.ts +1 -1
- package/dist/watch.js +14 -14
- package/docs/ADR-SVG-INTRGRATION-METHODS-001.adr.md +157 -0
- package/docs/ADR-SVG-INTRGRATION-METHODS-002.adr.md +550 -0
- package/docs/FRAMEWORK-GUIDE.md +768 -0
- package/docs/IMPLEMENTATION-SUMMARY.md +376 -0
- package/docs/TDR-SVG-INTRGRATION-METHODS-001.tdr.md +115 -0
- package/package.json +155 -14
package/dist/index.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export { ConfigService, configService } from './services/config.js';
|
|
|
22
22
|
* Error Handler - Comprehensive error management with recovery strategies
|
|
23
23
|
* Provides: structured error handling, recovery mechanisms, and user-friendly messages
|
|
24
24
|
*/
|
|
25
|
-
export { SVGErrorHandler, errorHandler, withErrorHandling, handleErrors } from './core/error-handler.js';
|
|
25
|
+
export { SVGErrorHandler, errorHandler, withErrorHandling, handleErrors, } from './core/error-handler.js';
|
|
26
26
|
/**
|
|
27
27
|
* SVG Processor - Core SVG content processing and React component generation
|
|
28
28
|
* Provides: SVG parsing, optimization, React component generation, and batch processing
|
|
@@ -32,7 +32,7 @@ export { SVGProcessor, svgProcessor } from './processors/svg-processor.js';
|
|
|
32
32
|
* Performance Engine - Advanced optimization for batch processing and parallel execution
|
|
33
33
|
* Provides: batch processing, caching, memory optimization, and performance monitoring
|
|
34
34
|
*/
|
|
35
|
-
export { PerformanceEngine, performanceEngine } from './core/performance-engine.js';
|
|
35
|
+
export { PerformanceEngine, performanceEngine, } from './core/performance-engine.js';
|
|
36
36
|
/**
|
|
37
37
|
* Style Compiler - Comprehensive styling system with responsive design and theming
|
|
38
38
|
* Provides: CSS generation, theme management, responsive values, and style optimization
|
|
@@ -47,7 +47,7 @@ export { TemplateManager, templateManager } from './core/template-manager.js';
|
|
|
47
47
|
* Framework Template Engine - Universal template generator supporting multiple UI frameworks
|
|
48
48
|
* Provides: React, Vue, Svelte, Angular, Solid, Preact, Lit, and Vanilla JS components
|
|
49
49
|
*/
|
|
50
|
-
export { FrameworkTemplateEngine, frameworkTemplateEngine, type
|
|
50
|
+
export { FrameworkTemplateEngine, frameworkTemplateEngine, type FrameworkOptions, } from './core/framework-templates.js';
|
|
51
51
|
/**
|
|
52
52
|
* Plugin Manager - Extensible plugin system for SVG processing enhancements
|
|
53
53
|
* Provides: plugin registration, lifecycle management, and content processing pipeline
|
|
@@ -57,7 +57,7 @@ export { PluginManager, pluginManager } from './core/plugin-manager.js';
|
|
|
57
57
|
* Native Node.js Utilities - Zero-dependency replacements for external libraries
|
|
58
58
|
* Provides: file operations, string manipulation, CLI parsing, and file watching
|
|
59
59
|
*/
|
|
60
|
-
export { toPascalCase, FileSystem, CLI, FileWatcher } from './utils/native.js';
|
|
60
|
+
export { toPascalCase, toCamelCase, toKebabCase, FileSystem, CLI, FileWatcher, } from './utils/native.js';
|
|
61
61
|
/**
|
|
62
62
|
* File System Lock Functions - Concurrent file operation safety with advisory locking
|
|
63
63
|
* Provides: file locking, unlocking, and lock status checking for safe concurrent access
|
|
@@ -82,7 +82,7 @@ export { clean } from './clean.js';
|
|
|
82
82
|
* TypeScript Type Definitions - Comprehensive type system for all interfaces and configurations
|
|
83
83
|
* Provides: complete type safety for all operations, configurations, and data structures
|
|
84
84
|
*/
|
|
85
|
-
export type { SVGConfig, ComponentGenerationOptions, SVGProcessorResult, ProcessingJob, ProcessingStatus, Plugin, PluginConfig, Template, TemplateConfig, WatchOptions } from './types/index.js';
|
|
85
|
+
export type { SVGConfig, ComponentGenerationOptions, OutputConfig, NamingConvention, FrameworkType, SVGProcessorResult, ProcessingJob, ProcessingStatus, Plugin, PluginConfig, Template, TemplateConfig, WatchOptions, } from './types/index.js';
|
|
86
86
|
/**
|
|
87
87
|
* Error handling types - Available from core error handler
|
|
88
88
|
*/
|
|
@@ -104,7 +104,9 @@ export declare const SVGER: {
|
|
|
104
104
|
/**
|
|
105
105
|
* Process single SVG file to React component
|
|
106
106
|
*/
|
|
107
|
-
readonly processFile: (svgFilePath: string, outputDir: string, options?: Partial<import("./types/index.js").ComponentGenerationOptions
|
|
107
|
+
readonly processFile: (svgFilePath: string, outputDir: string, options?: Partial<import("./types/index.js").ComponentGenerationOptions & {
|
|
108
|
+
namingConvention?: import("./types/index.js").NamingConvention;
|
|
109
|
+
}>) => Promise<import("./types/index.js").SVGProcessorResult>;
|
|
108
110
|
/**
|
|
109
111
|
* Process multiple SVG files in batch
|
|
110
112
|
*/
|
package/dist/index.js
CHANGED
|
@@ -25,7 +25,7 @@ export { ConfigService, configService } from './services/config.js';
|
|
|
25
25
|
* Error Handler - Comprehensive error management with recovery strategies
|
|
26
26
|
* Provides: structured error handling, recovery mechanisms, and user-friendly messages
|
|
27
27
|
*/
|
|
28
|
-
export { SVGErrorHandler, errorHandler, withErrorHandling, handleErrors } from './core/error-handler.js';
|
|
28
|
+
export { SVGErrorHandler, errorHandler, withErrorHandling, handleErrors, } from './core/error-handler.js';
|
|
29
29
|
// ============================================================================
|
|
30
30
|
// PROCESSING ENGINES
|
|
31
31
|
// ============================================================================
|
|
@@ -38,7 +38,7 @@ export { SVGProcessor, svgProcessor } from './processors/svg-processor.js';
|
|
|
38
38
|
* Performance Engine - Advanced optimization for batch processing and parallel execution
|
|
39
39
|
* Provides: batch processing, caching, memory optimization, and performance monitoring
|
|
40
40
|
*/
|
|
41
|
-
export { PerformanceEngine, performanceEngine } from './core/performance-engine.js';
|
|
41
|
+
export { PerformanceEngine, performanceEngine, } from './core/performance-engine.js';
|
|
42
42
|
/**
|
|
43
43
|
* Style Compiler - Comprehensive styling system with responsive design and theming
|
|
44
44
|
* Provides: CSS generation, theme management, responsive values, and style optimization
|
|
@@ -56,7 +56,7 @@ export { TemplateManager, templateManager } from './core/template-manager.js';
|
|
|
56
56
|
* Framework Template Engine - Universal template generator supporting multiple UI frameworks
|
|
57
57
|
* Provides: React, Vue, Svelte, Angular, Solid, Preact, Lit, and Vanilla JS components
|
|
58
58
|
*/
|
|
59
|
-
export { FrameworkTemplateEngine, frameworkTemplateEngine } from './core/framework-templates.js';
|
|
59
|
+
export { FrameworkTemplateEngine, frameworkTemplateEngine, } from './core/framework-templates.js';
|
|
60
60
|
// ============================================================================
|
|
61
61
|
// PLUGIN ARCHITECTURE
|
|
62
62
|
// ============================================================================
|
|
@@ -72,7 +72,7 @@ export { PluginManager, pluginManager } from './core/plugin-manager.js';
|
|
|
72
72
|
* Native Node.js Utilities - Zero-dependency replacements for external libraries
|
|
73
73
|
* Provides: file operations, string manipulation, CLI parsing, and file watching
|
|
74
74
|
*/
|
|
75
|
-
export { toPascalCase, FileSystem, CLI, FileWatcher } from './utils/native.js';
|
|
75
|
+
export { toPascalCase, toCamelCase, toKebabCase, FileSystem, CLI, FileWatcher, } from './utils/native.js';
|
|
76
76
|
/**
|
|
77
77
|
* File System Lock Functions - Concurrent file operation safety with advisory locking
|
|
78
78
|
* Provides: file locking, unlocking, and lock status checking for safe concurrent access
|
|
@@ -137,7 +137,7 @@ export const SVGER = {
|
|
|
137
137
|
/**
|
|
138
138
|
* Build all SVG files in directory
|
|
139
139
|
*/
|
|
140
|
-
build: buildAll
|
|
140
|
+
build: buildAll,
|
|
141
141
|
};
|
|
142
142
|
// ============================================================================
|
|
143
143
|
// VERSION INFORMATION
|
package/dist/lock.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import fs from
|
|
2
|
-
import path from
|
|
3
|
-
const LOCK_FILE =
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
const LOCK_FILE = '.svg-lock';
|
|
4
4
|
/**
|
|
5
5
|
* Get the absolute path to the lock file.
|
|
6
6
|
*
|
|
@@ -18,7 +18,7 @@ function readLockFile() {
|
|
|
18
18
|
if (!fs.existsSync(getLockFilePath()))
|
|
19
19
|
return [];
|
|
20
20
|
try {
|
|
21
|
-
const data = fs.readFileSync(getLockFilePath(),
|
|
21
|
+
const data = fs.readFileSync(getLockFilePath(), 'utf-8');
|
|
22
22
|
return JSON.parse(data);
|
|
23
23
|
}
|
|
24
24
|
catch (e) {
|
|
@@ -31,7 +31,7 @@ function readLockFile() {
|
|
|
31
31
|
* @param {string[]} files - Array of SVG file names to lock.
|
|
32
32
|
*/
|
|
33
33
|
function writeLockFile(files) {
|
|
34
|
-
fs.writeFileSync(getLockFilePath(), JSON.stringify(files, null, 2),
|
|
34
|
+
fs.writeFileSync(getLockFilePath(), JSON.stringify(files, null, 2), 'utf-8');
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
37
|
* Lock one or more SVG files to prevent them from being processed.
|
|
@@ -43,7 +43,7 @@ export function lockFiles(files) {
|
|
|
43
43
|
const current = readLockFile();
|
|
44
44
|
const newFiles = Array.from(new Set([...current, ...fileNames]));
|
|
45
45
|
writeLockFile(newFiles);
|
|
46
|
-
console.log(`🔒 Locked files: ${newFiles.join(
|
|
46
|
+
console.log(`🔒 Locked files: ${newFiles.join(', ')}`);
|
|
47
47
|
}
|
|
48
48
|
/**
|
|
49
49
|
* Unlock one or more SVG files, allowing them to be processed again.
|
|
@@ -55,7 +55,7 @@ export function unlockFiles(files) {
|
|
|
55
55
|
const current = readLockFile();
|
|
56
56
|
const remaining = current.filter(f => !fileNames.includes(f));
|
|
57
57
|
writeLockFile(remaining);
|
|
58
|
-
console.log(`🔓 Unlocked files: ${fileNames.join(
|
|
58
|
+
console.log(`🔓 Unlocked files: ${fileNames.join(', ')}`);
|
|
59
59
|
}
|
|
60
60
|
/**
|
|
61
61
|
* Check if a specific SVG file is locked.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ComponentGenerationOptions, SVGProcessorResult } from '../types/index.js';
|
|
1
|
+
import { ComponentGenerationOptions, SVGProcessorResult, NamingConvention } from '../types/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* SVG content processor and component generator
|
|
4
4
|
*/
|
|
@@ -19,7 +19,7 @@ export declare class SVGProcessor {
|
|
|
19
19
|
/**
|
|
20
20
|
* Generate component name from filename
|
|
21
21
|
*/
|
|
22
|
-
generateComponentName(fileName: string): string;
|
|
22
|
+
generateComponentName(fileName: string, namingConvention?: 'kebab' | 'pascal' | 'camel'): string;
|
|
23
23
|
/**
|
|
24
24
|
* Generate React component from SVG content
|
|
25
25
|
*/
|
|
@@ -45,10 +45,16 @@ export declare class SVGProcessor {
|
|
|
45
45
|
error?: Error;
|
|
46
46
|
duration: number;
|
|
47
47
|
}>>;
|
|
48
|
+
/**
|
|
49
|
+
* Generate filename from component name using naming convention
|
|
50
|
+
*/
|
|
51
|
+
generateFileName(componentName: string, extension: string, namingConvention?: NamingConvention): string;
|
|
48
52
|
/**
|
|
49
53
|
* Process a single SVG file
|
|
50
54
|
*/
|
|
51
|
-
processSVGFile(svgFilePath: string, outputDir: string, options?: Partial<ComponentGenerationOptions
|
|
55
|
+
processSVGFile(svgFilePath: string, outputDir: string, options?: Partial<ComponentGenerationOptions & {
|
|
56
|
+
namingConvention?: NamingConvention;
|
|
57
|
+
}>): Promise<SVGProcessorResult>;
|
|
52
58
|
/**
|
|
53
59
|
* Get processing statistics
|
|
54
60
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
|
-
import { toPascalCase, FileSystem } from '../utils/native.js';
|
|
2
|
+
import { toPascalCase, toKebabCase, toCamelCase, FileSystem, } from '../utils/native.js';
|
|
3
3
|
import { logger } from '../core/logger.js';
|
|
4
4
|
import { performanceEngine } from '../core/performance-engine.js';
|
|
5
5
|
import { frameworkTemplateEngine } from '../core/framework-templates.js';
|
|
@@ -22,7 +22,7 @@ export class SVGProcessor {
|
|
|
22
22
|
*/
|
|
23
23
|
cleanSVGContent(svgContent) {
|
|
24
24
|
logger.debug('Cleaning SVG content');
|
|
25
|
-
return svgContent
|
|
25
|
+
return (svgContent
|
|
26
26
|
// Remove XML declaration
|
|
27
27
|
.replace(/<\?xml.*?\?>/g, '')
|
|
28
28
|
// Remove DOCTYPE declaration
|
|
@@ -52,7 +52,7 @@ export class SVGProcessor {
|
|
|
52
52
|
// Remove outer SVG tag and keep inner content
|
|
53
53
|
.trim()
|
|
54
54
|
.replace(/^<svg[^>]*>([\s\S]*)<\/svg>$/i, '$1')
|
|
55
|
-
.trim();
|
|
55
|
+
.trim());
|
|
56
56
|
}
|
|
57
57
|
/**
|
|
58
58
|
* Extract viewBox from SVG content
|
|
@@ -64,14 +64,27 @@ export class SVGProcessor {
|
|
|
64
64
|
/**
|
|
65
65
|
* Generate component name from filename
|
|
66
66
|
*/
|
|
67
|
-
generateComponentName(fileName) {
|
|
67
|
+
generateComponentName(fileName, namingConvention) {
|
|
68
68
|
const baseName = path.basename(fileName, '.svg');
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
// Apply naming convention if specified, otherwise default to PascalCase
|
|
70
|
+
switch (namingConvention) {
|
|
71
|
+
case 'kebab':
|
|
72
|
+
// Keep kebab-case for filename, but component still needs PascalCase
|
|
73
|
+
return toPascalCase(baseName);
|
|
74
|
+
case 'camel':
|
|
75
|
+
// Convert to camelCase
|
|
76
|
+
const pascalName = toPascalCase(baseName);
|
|
77
|
+
return pascalName.charAt(0).toLowerCase() + pascalName.slice(1);
|
|
78
|
+
case 'pascal':
|
|
79
|
+
default:
|
|
80
|
+
// Default to PascalCase
|
|
81
|
+
const componentName = toPascalCase(baseName);
|
|
82
|
+
// Ensure component name starts with uppercase letter
|
|
83
|
+
if (!/^[A-Z]/.test(componentName)) {
|
|
84
|
+
return `Svg${componentName}`;
|
|
85
|
+
}
|
|
86
|
+
return componentName;
|
|
73
87
|
}
|
|
74
|
-
return componentName;
|
|
75
88
|
}
|
|
76
89
|
/**
|
|
77
90
|
* Generate React component from SVG content
|
|
@@ -88,7 +101,7 @@ export class SVGProcessor {
|
|
|
88
101
|
svgContent: processedContent,
|
|
89
102
|
framework: options.framework || 'react',
|
|
90
103
|
typescript: options.typescript !== undefined ? options.typescript : true,
|
|
91
|
-
...options
|
|
104
|
+
...options,
|
|
92
105
|
};
|
|
93
106
|
// Use framework template engine directly
|
|
94
107
|
const component = frameworkTemplateEngine.generateComponent(fullOptions);
|
|
@@ -112,7 +125,7 @@ export class SVGProcessor {
|
|
|
112
125
|
const component = frameworkTemplateEngine.generateComponent({
|
|
113
126
|
...options,
|
|
114
127
|
componentName,
|
|
115
|
-
svgContent: optimizedContent
|
|
128
|
+
svgContent: optimizedContent,
|
|
116
129
|
});
|
|
117
130
|
logger.debug(`Generated ${options.framework} component: ${componentName}`);
|
|
118
131
|
return component;
|
|
@@ -141,6 +154,26 @@ export class SVGProcessor {
|
|
|
141
154
|
throw error;
|
|
142
155
|
}
|
|
143
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* Generate filename from component name using naming convention
|
|
159
|
+
*/
|
|
160
|
+
generateFileName(componentName, extension, namingConvention) {
|
|
161
|
+
let fileName;
|
|
162
|
+
switch (namingConvention) {
|
|
163
|
+
case 'kebab':
|
|
164
|
+
fileName = toKebabCase(componentName);
|
|
165
|
+
break;
|
|
166
|
+
case 'camel':
|
|
167
|
+
fileName = toCamelCase(componentName);
|
|
168
|
+
break;
|
|
169
|
+
case 'pascal':
|
|
170
|
+
default:
|
|
171
|
+
// Default to PascalCase (same as component name)
|
|
172
|
+
fileName = componentName;
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
return `${fileName}.${extension}`;
|
|
176
|
+
}
|
|
144
177
|
/**
|
|
145
178
|
* Process a single SVG file
|
|
146
179
|
*/
|
|
@@ -150,14 +183,14 @@ export class SVGProcessor {
|
|
|
150
183
|
id: jobId,
|
|
151
184
|
filePath: svgFilePath,
|
|
152
185
|
status: 'processing',
|
|
153
|
-
startTime: Date.now()
|
|
186
|
+
startTime: Date.now(),
|
|
154
187
|
};
|
|
155
188
|
this.processingQueue.set(jobId, job);
|
|
156
189
|
logger.debug(`Processing SVG file: ${svgFilePath}`);
|
|
157
190
|
try {
|
|
158
191
|
// Read SVG content
|
|
159
192
|
const svgContent = await FileSystem.readFile(svgFilePath, 'utf-8');
|
|
160
|
-
// Generate component name
|
|
193
|
+
// Generate component name (always PascalCase for component)
|
|
161
194
|
const componentName = this.generateComponentName(path.basename(svgFilePath));
|
|
162
195
|
// Generate component code
|
|
163
196
|
const componentCode = await this.generateComponent(componentName, svgContent, options);
|
|
@@ -167,8 +200,11 @@ export class SVGProcessor {
|
|
|
167
200
|
const framework = options.framework || 'react';
|
|
168
201
|
const typescript = options.typescript !== undefined ? options.typescript : true;
|
|
169
202
|
const fileExtension = frameworkTemplateEngine.getFileExtension(framework, typescript);
|
|
203
|
+
// Generate filename using naming convention
|
|
204
|
+
const namingConvention = options.namingConvention;
|
|
205
|
+
const fileName = this.generateFileName(componentName, fileExtension, namingConvention);
|
|
170
206
|
// Write component file
|
|
171
|
-
const outputFilePath = path.join(outputDir,
|
|
207
|
+
const outputFilePath = path.join(outputDir, fileName);
|
|
172
208
|
await FileSystem.writeFile(outputFilePath, componentCode, 'utf-8');
|
|
173
209
|
// Update job status
|
|
174
210
|
job.status = 'completed';
|
|
@@ -176,9 +212,9 @@ export class SVGProcessor {
|
|
|
176
212
|
const result = {
|
|
177
213
|
success: true,
|
|
178
214
|
componentName,
|
|
179
|
-
filePath: outputFilePath
|
|
215
|
+
filePath: outputFilePath,
|
|
180
216
|
};
|
|
181
|
-
logger.success(`Generated component: ${
|
|
217
|
+
logger.success(`Generated component: ${fileName}`);
|
|
182
218
|
return result;
|
|
183
219
|
}
|
|
184
220
|
catch (error) {
|
|
@@ -189,7 +225,7 @@ export class SVGProcessor {
|
|
|
189
225
|
success: false,
|
|
190
226
|
componentName: '',
|
|
191
227
|
filePath: svgFilePath,
|
|
192
|
-
error: error
|
|
228
|
+
error: error,
|
|
193
229
|
};
|
|
194
230
|
logger.error(`Failed to process ${svgFilePath}:`, error);
|
|
195
231
|
return result;
|
package/dist/services/config.js
CHANGED
|
@@ -35,25 +35,25 @@ export class ConfigService {
|
|
|
35
35
|
},
|
|
36
36
|
plugins: [],
|
|
37
37
|
template: {
|
|
38
|
-
type: 'default'
|
|
38
|
+
type: 'default',
|
|
39
39
|
},
|
|
40
40
|
frameworkOptions: {
|
|
41
41
|
forwardRef: true,
|
|
42
42
|
memo: false,
|
|
43
43
|
scriptSetup: true,
|
|
44
|
-
standalone: true
|
|
44
|
+
standalone: true,
|
|
45
45
|
},
|
|
46
46
|
errorHandling: {
|
|
47
47
|
skipOnError: false,
|
|
48
48
|
logLevel: 'info',
|
|
49
|
-
maxRetries: 3
|
|
49
|
+
maxRetries: 3,
|
|
50
50
|
},
|
|
51
51
|
performance: {
|
|
52
52
|
batchSize: 10,
|
|
53
53
|
parallel: true,
|
|
54
54
|
timeout: 30000,
|
|
55
|
-
enableCache: true
|
|
56
|
-
}
|
|
55
|
+
enableCache: true,
|
|
56
|
+
},
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
59
|
/**
|
|
@@ -79,7 +79,7 @@ export class ConfigService {
|
|
|
79
79
|
// Merge with defaults to ensure all required properties exist
|
|
80
80
|
this.cachedConfig = {
|
|
81
81
|
...this.getDefaultConfig(),
|
|
82
|
-
...configData
|
|
82
|
+
...configData,
|
|
83
83
|
};
|
|
84
84
|
logger.debug('Configuration loaded successfully');
|
|
85
85
|
return this.cachedConfig;
|
|
@@ -165,7 +165,8 @@ export class ConfigService {
|
|
|
165
165
|
// Required string fields
|
|
166
166
|
const requiredStringFields = ['source', 'output', 'defaultFill'];
|
|
167
167
|
for (const field of requiredStringFields) {
|
|
168
|
-
if (!configToValidate[field] ||
|
|
168
|
+
if (!configToValidate[field] ||
|
|
169
|
+
typeof configToValidate[field] !== 'string') {
|
|
169
170
|
errors.push(`${field} must be a non-empty string`);
|
|
170
171
|
}
|
|
171
172
|
}
|
|
@@ -182,12 +183,13 @@ export class ConfigService {
|
|
|
182
183
|
errors.push('exclude must be an array');
|
|
183
184
|
}
|
|
184
185
|
// Validate styleRules object
|
|
185
|
-
if (configToValidate.styleRules &&
|
|
186
|
+
if (configToValidate.styleRules &&
|
|
187
|
+
typeof configToValidate.styleRules !== 'object') {
|
|
186
188
|
errors.push('styleRules must be an object');
|
|
187
189
|
}
|
|
188
190
|
return {
|
|
189
191
|
valid: errors.length === 0,
|
|
190
|
-
errors
|
|
192
|
+
errors,
|
|
191
193
|
};
|
|
192
194
|
}
|
|
193
195
|
/**
|
|
@@ -30,7 +30,7 @@ export class FileWatcherService {
|
|
|
30
30
|
try {
|
|
31
31
|
const watcher = fs.watch(resolvedPath, {
|
|
32
32
|
persistent: true,
|
|
33
|
-
recursive: false
|
|
33
|
+
recursive: false,
|
|
34
34
|
}, (eventType, filename) => {
|
|
35
35
|
if (filename) {
|
|
36
36
|
this.handleFileEvent(watchId, eventType, path.join(resolvedPath, filename));
|
|
@@ -83,7 +83,7 @@ export class FileWatcherService {
|
|
|
83
83
|
const event = {
|
|
84
84
|
type: actualEventType,
|
|
85
85
|
filePath,
|
|
86
|
-
timestamp: Date.now()
|
|
86
|
+
timestamp: Date.now(),
|
|
87
87
|
};
|
|
88
88
|
logger.debug(`File event: ${actualEventType} - ${path.basename(filePath)}`);
|
|
89
89
|
// Emit event to registered handlers
|
|
@@ -160,7 +160,7 @@ export class FileWatcherService {
|
|
|
160
160
|
return {
|
|
161
161
|
activeWatchers: this.watchers.size,
|
|
162
162
|
pendingEvents: this.debounceTimers.size,
|
|
163
|
-
totalHandlers
|
|
163
|
+
totalHandlers,
|
|
164
164
|
};
|
|
165
165
|
}
|
|
166
166
|
/**
|
|
@@ -41,9 +41,15 @@ export class SVGService {
|
|
|
41
41
|
...config,
|
|
42
42
|
...(options.config || {}),
|
|
43
43
|
// Support direct properties on options for CLI convenience
|
|
44
|
-
...options.framework && {
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
...(options.framework && {
|
|
45
|
+
framework: options.framework,
|
|
46
|
+
}),
|
|
47
|
+
...(options.typescript !== undefined && {
|
|
48
|
+
typescript: options.typescript,
|
|
49
|
+
}),
|
|
50
|
+
...(options.frameworkOptions && {
|
|
51
|
+
frameworkOptions: options.frameworkOptions,
|
|
52
|
+
}),
|
|
47
53
|
};
|
|
48
54
|
// Read all SVG files
|
|
49
55
|
const files = await FileSystem.readDir(srcDir);
|
|
@@ -70,12 +76,12 @@ export class SVGService {
|
|
|
70
76
|
defaultWidth: mergedConfig.defaultWidth,
|
|
71
77
|
defaultHeight: mergedConfig.defaultHeight,
|
|
72
78
|
defaultFill: mergedConfig.defaultFill,
|
|
73
|
-
styleRules: Object.fromEntries(Object.entries(mergedConfig.styleRules || {}).filter(([_, v]) => v !== undefined))
|
|
79
|
+
styleRules: Object.fromEntries(Object.entries(mergedConfig.styleRules || {}).filter(([_, v]) => v !== undefined)),
|
|
74
80
|
});
|
|
75
81
|
results.push({
|
|
76
82
|
success: processingResult.success,
|
|
77
83
|
file,
|
|
78
|
-
error: processingResult.error
|
|
84
|
+
error: processingResult.error,
|
|
79
85
|
});
|
|
80
86
|
}
|
|
81
87
|
catch (error) {
|
|
@@ -83,7 +89,7 @@ export class SVGService {
|
|
|
83
89
|
results.push({
|
|
84
90
|
success: false,
|
|
85
91
|
file,
|
|
86
|
-
error: error
|
|
92
|
+
error: error,
|
|
87
93
|
});
|
|
88
94
|
}
|
|
89
95
|
}
|
|
@@ -93,7 +99,9 @@ export class SVGService {
|
|
|
93
99
|
logger.info(`Build complete: ${successful} successful, ${failed} failed`);
|
|
94
100
|
if (failed > 0) {
|
|
95
101
|
logger.warn('Some files failed to process:');
|
|
96
|
-
results
|
|
102
|
+
results
|
|
103
|
+
.filter(r => !r.success)
|
|
104
|
+
.forEach(r => {
|
|
97
105
|
logger.warn(` - ${r.file}: ${r.error?.message}`);
|
|
98
106
|
});
|
|
99
107
|
}
|
|
@@ -126,7 +134,7 @@ export class SVGService {
|
|
|
126
134
|
defaultWidth: mergedConfig.defaultWidth,
|
|
127
135
|
defaultHeight: mergedConfig.defaultHeight,
|
|
128
136
|
defaultFill: mergedConfig.defaultFill,
|
|
129
|
-
styleRules: Object.fromEntries(Object.entries(mergedConfig.styleRules || {}).filter(([_, v]) => v !== undefined))
|
|
137
|
+
styleRules: Object.fromEntries(Object.entries(mergedConfig.styleRules || {}).filter(([_, v]) => v !== undefined)),
|
|
130
138
|
});
|
|
131
139
|
if (!result.success) {
|
|
132
140
|
throw result.error || new Error('Failed to generate component');
|
|
@@ -194,7 +202,7 @@ export class SVGService {
|
|
|
194
202
|
defaultWidth: mergedConfig.defaultWidth,
|
|
195
203
|
defaultHeight: mergedConfig.defaultHeight,
|
|
196
204
|
defaultFill: mergedConfig.defaultFill,
|
|
197
|
-
styleRules: Object.fromEntries(Object.entries(mergedConfig.styleRules || {}).filter(([_, v]) => v !== undefined))
|
|
205
|
+
styleRules: Object.fromEntries(Object.entries(mergedConfig.styleRules || {}).filter(([_, v]) => v !== undefined)),
|
|
198
206
|
});
|
|
199
207
|
}
|
|
200
208
|
catch (error) {
|
|
@@ -267,7 +275,9 @@ export class SVGService {
|
|
|
267
275
|
* Generate the content for index.ts file
|
|
268
276
|
*/
|
|
269
277
|
generateIndexContent(componentNames) {
|
|
270
|
-
const imports = componentNames
|
|
278
|
+
const imports = componentNames
|
|
279
|
+
.map(name => `export { default as ${name} } from './${name}';`)
|
|
280
|
+
.join('\n');
|
|
271
281
|
const exportAll = `
|
|
272
282
|
// Export all components
|
|
273
283
|
export {
|
|
@@ -300,7 +310,7 @@ ${imports}${exportAll}`;
|
|
|
300
310
|
return {
|
|
301
311
|
activeWatchers: this.activeWatchers.size,
|
|
302
312
|
processingQueue: svgProcessor.getProcessingStats(),
|
|
303
|
-
watcherStats: fileWatcher.getWatchStats()
|
|
313
|
+
watcherStats: fileWatcher.getWatchStats(),
|
|
304
314
|
};
|
|
305
315
|
}
|
|
306
316
|
/**
|
|
@@ -346,7 +356,9 @@ export class LockService {
|
|
|
346
356
|
}
|
|
347
357
|
writeLockFile(locks) {
|
|
348
358
|
try {
|
|
349
|
-
FileSystem.writeJSONSync(this.getLockFilePath(), Array.from(locks), {
|
|
359
|
+
FileSystem.writeJSONSync(this.getLockFilePath(), Array.from(locks), {
|
|
360
|
+
spaces: 2,
|
|
361
|
+
});
|
|
350
362
|
this.cachedLocks = locks;
|
|
351
363
|
}
|
|
352
364
|
catch (error) {
|
|
@@ -13,32 +13,32 @@
|
|
|
13
13
|
* @param [options.defaultFill="currentColor"] - The default fill color for the SVG.
|
|
14
14
|
* @returns A string containing the complete TypeScript code for the React SVG component.
|
|
15
15
|
*/
|
|
16
|
-
export function reactTemplate({ componentName, svgContent, defaultWidth = 24, defaultHeight = 24, defaultFill =
|
|
16
|
+
export function reactTemplate({ componentName, svgContent, defaultWidth = 24, defaultHeight = 24, defaultFill = 'currentColor', }) {
|
|
17
17
|
const cleaned = svgContent
|
|
18
|
-
.replace(/<\?xml.*?\?>/g,
|
|
19
|
-
.replace(/<!DOCTYPE.*?>/g,
|
|
20
|
-
.replace(/\r?\n|\r/g,
|
|
21
|
-
.replace(/\s{2,}/g,
|
|
22
|
-
.replace(/style="[^"]*"/g,
|
|
23
|
-
.replace(/\s+xmlns(:xlink)?="[^"]*"/g,
|
|
18
|
+
.replace(/<\?xml.*?\?>/g, '')
|
|
19
|
+
.replace(/<!DOCTYPE.*?>/g, '')
|
|
20
|
+
.replace(/\r?\n|\r/g, '')
|
|
21
|
+
.replace(/\s{2,}/g, ' ')
|
|
22
|
+
.replace(/style="[^"]*"/g, '')
|
|
23
|
+
.replace(/\s+xmlns(:xlink)?="[^"]*"/g, '')
|
|
24
24
|
.trim()
|
|
25
|
-
.replace(/^.*?<svg[^>]*>(.*?)<\/svg>.*$/i,
|
|
26
|
-
return `import type { SVGProps } from "react";
|
|
27
|
-
const Svg${componentName} = (props: SVGProps<SVGSVGElement>) => (
|
|
28
|
-
<svg
|
|
29
|
-
viewBox="0 0 ${defaultWidth} ${defaultHeight}"
|
|
30
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
31
|
-
xmlnsXlink="http://www.w3.org/1999/xlink"
|
|
32
|
-
width={props.width || ${defaultWidth}}
|
|
33
|
-
height={props.height || ${defaultHeight}}
|
|
34
|
-
fill={props.fill || "${defaultFill}"}
|
|
35
|
-
stroke={props.stroke || "none"}
|
|
36
|
-
className={props.className}
|
|
37
|
-
{...props}
|
|
38
|
-
>
|
|
39
|
-
${cleaned}
|
|
40
|
-
</svg>
|
|
41
|
-
);
|
|
42
|
-
export default Svg${componentName};
|
|
25
|
+
.replace(/^.*?<svg[^>]*>(.*?)<\/svg>.*$/i, '$1');
|
|
26
|
+
return `import type { SVGProps } from "react";
|
|
27
|
+
const Svg${componentName} = (props: SVGProps<SVGSVGElement>) => (
|
|
28
|
+
<svg
|
|
29
|
+
viewBox="0 0 ${defaultWidth} ${defaultHeight}"
|
|
30
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
31
|
+
xmlnsXlink="http://www.w3.org/1999/xlink"
|
|
32
|
+
width={props.width || ${defaultWidth}}
|
|
33
|
+
height={props.height || ${defaultHeight}}
|
|
34
|
+
fill={props.fill || "${defaultFill}"}
|
|
35
|
+
stroke={props.stroke || "none"}
|
|
36
|
+
className={props.className}
|
|
37
|
+
{...props}
|
|
38
|
+
>
|
|
39
|
+
${cleaned}
|
|
40
|
+
</svg>
|
|
41
|
+
);
|
|
42
|
+
export default Svg${componentName};
|
|
43
43
|
`;
|
|
44
44
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -2,9 +2,15 @@
|
|
|
2
2
|
* Type definitions for svger-cli
|
|
3
3
|
*/
|
|
4
4
|
export type FrameworkType = 'react' | 'vue' | 'svelte' | 'angular' | 'solid' | 'preact' | 'lit' | 'vanilla';
|
|
5
|
+
export type NamingConvention = 'kebab' | 'pascal' | 'camel';
|
|
6
|
+
export interface OutputConfig {
|
|
7
|
+
naming?: NamingConvention;
|
|
8
|
+
extension?: string;
|
|
9
|
+
directory?: string;
|
|
10
|
+
}
|
|
5
11
|
export interface SVGConfig {
|
|
6
12
|
source: string;
|
|
7
|
-
output: string;
|
|
13
|
+
output: string | OutputConfig;
|
|
8
14
|
watch: boolean;
|
|
9
15
|
framework: FrameworkType;
|
|
10
16
|
typescript: boolean;
|
package/dist/utils/native.d.ts
CHANGED
|
@@ -2,9 +2,39 @@
|
|
|
2
2
|
* Native Node.js utilities to replace external dependencies
|
|
3
3
|
*/
|
|
4
4
|
/**
|
|
5
|
-
* Convert string to PascalCase
|
|
5
|
+
* Convert a string to PascalCase.
|
|
6
|
+
* Handles kebab-case, snake_case, and space-separated strings.
|
|
7
|
+
*
|
|
8
|
+
* @param {string} str - Input string to convert.
|
|
9
|
+
* @returns {string} PascalCase string.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* toPascalCase('hello-world') => 'HelloWorld'
|
|
13
|
+
* toPascalCase('hello_world') => 'HelloWorld'
|
|
14
|
+
* toPascalCase('hello world') => 'HelloWorld'
|
|
6
15
|
*/
|
|
7
16
|
export declare function toPascalCase(str: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Convert a string to camelCase.
|
|
19
|
+
*
|
|
20
|
+
* @param {string} str - Input string to convert.
|
|
21
|
+
* @returns {string} camelCase string.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* toCamelCase('hello-world') => 'helloWorld'
|
|
25
|
+
*/
|
|
26
|
+
export declare function toCamelCase(str: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* Convert a string to kebab-case.
|
|
29
|
+
*
|
|
30
|
+
* @param {string} str - Input string to convert.
|
|
31
|
+
* @returns {string} kebab-case string.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* toKebabCase('HelloWorld') => 'hello-world'
|
|
35
|
+
* toKebabCase('hello_world') => 'hello-world'
|
|
36
|
+
*/
|
|
37
|
+
export declare function toKebabCase(str: string): string;
|
|
8
38
|
/**
|
|
9
39
|
* Native file system utilities (replaces fs-extra package)
|
|
10
40
|
*/
|