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
@@ -1,288 +0,0 @@
1
- import path from 'path';
2
- import { toPascalCase, FileSystem } from '../utils/native.js';
3
- import { ComponentGenerationOptions, SVGProcessorResult, ProcessingJob, ProcessingStatus } from '../types/index.js';
4
- import { logger } from '../core/logger.js';
5
- import { pluginManager } from '../core/plugin-manager.js';
6
- import { templateManager } from '../core/template-manager.js';
7
- import { performanceEngine } from '../core/performance-engine.js';
8
- import { frameworkTemplateEngine } from '../core/framework-templates.js';
9
-
10
- /**
11
- * SVG content processor and component generator
12
- */
13
- export class SVGProcessor {
14
- private static instance: SVGProcessor;
15
- private processingQueue: Map<string, ProcessingJob> = new Map();
16
- private jobCounter = 0;
17
-
18
- private constructor() {}
19
-
20
- public static getInstance(): SVGProcessor {
21
- if (!SVGProcessor.instance) {
22
- SVGProcessor.instance = new SVGProcessor();
23
- }
24
- return SVGProcessor.instance;
25
- }
26
-
27
- /**
28
- * Clean and optimize SVG content
29
- */
30
- public cleanSVGContent(svgContent: string): string {
31
- logger.debug('Cleaning SVG content');
32
-
33
- return svgContent
34
- // Remove XML declaration
35
- .replace(/<\?xml.*?\?>/g, '')
36
- // Remove DOCTYPE declaration
37
- .replace(/<!DOCTYPE.*?>/g, '')
38
- // Remove comments
39
- .replace(/<!--[\s\S]*?-->/g, '')
40
- // Normalize whitespace
41
- .replace(/\r?\n|\r/g, '')
42
- .replace(/\s{2,}/g, ' ')
43
- // Remove inline styles (they interfere with React styling)
44
- .replace(/style="[^"]*"/g, '')
45
- // Remove xmlns attributes (React will handle these)
46
- .replace(/\s+xmlns(:xlink)?="[^"]*"/g, '')
47
- // Convert attributes to camelCase for React
48
- .replace(/fill-rule/g, 'fillRule')
49
- .replace(/clip-rule/g, 'clipRule')
50
- .replace(/stroke-width/g, 'strokeWidth')
51
- .replace(/stroke-linecap/g, 'strokeLinecap')
52
- .replace(/stroke-linejoin/g, 'strokeLinejoin')
53
- .replace(/stroke-miterlimit/g, 'strokeMiterlimit')
54
- .replace(/stroke-dasharray/g, 'strokeDasharray')
55
- .replace(/stroke-dashoffset/g, 'strokeDashoffset')
56
- .replace(/font-family/g, 'fontFamily')
57
- .replace(/font-size/g, 'fontSize')
58
- .replace(/font-weight/g, 'fontWeight')
59
- .replace(/text-anchor/g, 'textAnchor')
60
- // Remove outer SVG tag and keep inner content
61
- .trim()
62
- .replace(/^<svg[^>]*>([\s\S]*)<\/svg>$/i, '$1')
63
- .trim();
64
- }
65
-
66
- /**
67
- * Extract viewBox from SVG content
68
- */
69
- public extractViewBox(svgContent: string): string | null {
70
- const viewBoxMatch = svgContent.match(/viewBox=["']([^"']+)["']/i);
71
- return viewBoxMatch ? viewBoxMatch[1] : null;
72
- }
73
-
74
- /**
75
- * Generate component name from filename
76
- */
77
- public generateComponentName(fileName: string): string {
78
- const baseName = path.basename(fileName, '.svg');
79
- const componentName = toPascalCase(baseName);
80
-
81
- // Ensure component name starts with uppercase letter
82
- if (!/^[A-Z]/.test(componentName)) {
83
- return `Svg${componentName}`;
84
- }
85
-
86
- return componentName;
87
- }
88
-
89
- /**
90
- * Generate React component from SVG content
91
- */
92
- public async generateComponent(
93
- componentName: string,
94
- svgContent: string,
95
- options: Partial<ComponentGenerationOptions> = {}
96
- ): Promise<string> {
97
- try {
98
- // Clean and optimize SVG content
99
- const cleanedContent = this.cleanSVGContent(svgContent);
100
-
101
- // Apply plugins (no plugin configs for now, just process directly)
102
- const processedContent = cleanedContent;
103
-
104
- // Create full options object with required fields
105
- const fullOptions: ComponentGenerationOptions = {
106
- componentName,
107
- svgContent: processedContent,
108
- framework: options.framework || 'react',
109
- typescript: options.typescript !== undefined ? options.typescript : true,
110
- ...options
111
- };
112
-
113
- // Use framework template engine directly
114
- const component = frameworkTemplateEngine.generateComponent(fullOptions);
115
-
116
- logger.debug(`Generated component: ${componentName}`);
117
- return component;
118
-
119
- } catch (error) {
120
- logger.error(`Failed to generate component ${componentName}:`, error);
121
- throw error;
122
- }
123
- }
124
-
125
- /**
126
- * Generate framework-agnostic component from SVG content
127
- */
128
- public async generateFrameworkComponent(
129
- componentName: string,
130
- svgContent: string,
131
- options: ComponentGenerationOptions
132
- ): Promise<string> {
133
- try {
134
- // Optimize SVG content based on framework requirements
135
- const optimizationLevel = options.framework === 'vanilla' ? 'maximum' : 'balanced';
136
- const optimizedContent = performanceEngine.optimizeSVGContent(svgContent, optimizationLevel);
137
-
138
- // Generate framework-specific component
139
- const component = frameworkTemplateEngine.generateComponent({
140
- ...options,
141
- componentName,
142
- svgContent: optimizedContent
143
- });
144
-
145
- logger.debug(`Generated ${options.framework} component: ${componentName}`);
146
- return component;
147
-
148
- } catch (error) {
149
- logger.error(`Failed to generate ${options.framework} component ${componentName}:`, error);
150
- throw error;
151
- }
152
- }
153
-
154
- /**
155
- * Process multiple SVG files in batch with performance optimization
156
- */
157
- public async processBatch(
158
- files: Array<{ path: string; outputDir: string; options?: Partial<ComponentGenerationOptions> }>,
159
- config: { batchSize?: number; parallel?: boolean; maxConcurrency?: number } = {}
160
- ): Promise<Array<{ success: boolean; filePath: string; error?: Error; duration: number }>> {
161
- logger.info(`Starting batch processing of ${files.length} files`);
162
-
163
- try {
164
- const results = await performanceEngine.processBatch(files, config);
165
-
166
- // Log performance metrics
167
- const metrics = performanceEngine.getPerformanceMetrics();
168
- if (metrics.memoryUsage.recommendations.length > 0) {
169
- logger.warn('Performance recommendations:', metrics.memoryUsage.recommendations);
170
- }
171
-
172
- return results;
173
- } catch (error) {
174
- logger.error('Batch processing failed:', error);
175
- throw error;
176
- }
177
- }
178
-
179
- /**
180
- * Process a single SVG file
181
- */
182
- public async processSVGFile(
183
- svgFilePath: string,
184
- outputDir: string,
185
- options: Partial<ComponentGenerationOptions> = {}
186
- ): Promise<SVGProcessorResult> {
187
- const jobId = `job-${++this.jobCounter}`;
188
- const job: ProcessingJob = {
189
- id: jobId,
190
- filePath: svgFilePath,
191
- status: 'processing',
192
- startTime: Date.now()
193
- };
194
-
195
- this.processingQueue.set(jobId, job);
196
- logger.debug(`Processing SVG file: ${svgFilePath}`);
197
-
198
- try {
199
- // Read SVG content
200
- const svgContent = await FileSystem.readFile(svgFilePath, 'utf-8');
201
-
202
- // Generate component name
203
- const componentName = this.generateComponentName(path.basename(svgFilePath));
204
-
205
- // Generate component code
206
- const componentCode = await this.generateComponent(
207
- componentName,
208
- svgContent,
209
- options
210
- );
211
-
212
- // Ensure output directory exists
213
- await FileSystem.ensureDir(outputDir);
214
-
215
- // Get correct file extension based on framework
216
- const framework = options.framework || 'react';
217
- const typescript = options.typescript !== undefined ? options.typescript : true;
218
- const fileExtension = frameworkTemplateEngine.getFileExtension(framework, typescript);
219
-
220
- // Write component file
221
- const outputFilePath = path.join(outputDir, `${componentName}.${fileExtension}`);
222
- await FileSystem.writeFile(outputFilePath, componentCode, 'utf-8');
223
-
224
- // Update job status
225
- job.status = 'completed';
226
- job.endTime = Date.now();
227
-
228
- const result: SVGProcessorResult = {
229
- success: true,
230
- componentName,
231
- filePath: outputFilePath
232
- };
233
-
234
- logger.success(`Generated component: ${componentName}.${fileExtension}`);
235
- return result;
236
-
237
- } catch (error) {
238
- job.status = 'failed';
239
- job.endTime = Date.now();
240
- job.error = error as Error;
241
-
242
- const result: SVGProcessorResult = {
243
- success: false,
244
- componentName: '',
245
- filePath: svgFilePath,
246
- error: error as Error
247
- };
248
-
249
- logger.error(`Failed to process ${svgFilePath}:`, error);
250
- return result;
251
- } finally {
252
- // Clean up completed jobs after some time
253
- setTimeout(() => {
254
- this.processingQueue.delete(jobId);
255
- }, 30000); // 30 seconds
256
- }
257
- }
258
-
259
- /**
260
- * Get processing statistics
261
- */
262
- public getProcessingStats(): {
263
- total: number;
264
- pending: number;
265
- processing: number;
266
- completed: number;
267
- failed: number;
268
- } {
269
- const jobs = Array.from(this.processingQueue.values());
270
- return {
271
- total: jobs.length,
272
- pending: jobs.filter(j => j.status === 'pending').length,
273
- processing: jobs.filter(j => j.status === 'processing').length,
274
- completed: jobs.filter(j => j.status === 'completed').length,
275
- failed: jobs.filter(j => j.status === 'failed').length,
276
- };
277
- }
278
-
279
- /**
280
- * Clear processing queue
281
- */
282
- public clearQueue(): void {
283
- this.processingQueue.clear();
284
- }
285
- }
286
-
287
- // Export singleton instance
288
- export const svgProcessor = SVGProcessor.getInstance();
@@ -1,241 +0,0 @@
1
- import path from 'path';
2
- import { FileSystem } from '../utils/native.js';
3
- import { SVGConfig } from '../types/index.js';
4
- import { logger } from '../core/logger.js';
5
-
6
- /**
7
- * Professional configuration management service
8
- */
9
- export class ConfigService {
10
- private static instance: ConfigService;
11
- private static readonly CONFIG_FILE = '.svgconfig.json';
12
- private cachedConfig: SVGConfig | null = null;
13
-
14
- private constructor() {}
15
-
16
- public static getInstance(): ConfigService {
17
- if (!ConfigService.instance) {
18
- ConfigService.instance = new ConfigService();
19
- }
20
- return ConfigService.instance;
21
- }
22
-
23
- /**
24
- * Get the default configuration
25
- */
26
- public getDefaultConfig(): SVGConfig {
27
- return {
28
- source: './src/assets/svg',
29
- output: './src/components/icons',
30
- framework: 'react',
31
- typescript: true,
32
- watch: false,
33
- defaultWidth: 24,
34
- defaultHeight: 24,
35
- defaultFill: 'currentColor',
36
- exclude: [],
37
- styleRules: {
38
- fill: 'inherit',
39
- stroke: 'none',
40
- },
41
- plugins: [],
42
- template: {
43
- type: 'default'
44
- },
45
- frameworkOptions: {
46
- forwardRef: true,
47
- memo: false,
48
- scriptSetup: true,
49
- standalone: true
50
- },
51
- errorHandling: {
52
- skipOnError: false,
53
- logLevel: 'info',
54
- maxRetries: 3
55
- },
56
- performance: {
57
- batchSize: 10,
58
- parallel: true,
59
- timeout: 30000,
60
- enableCache: true
61
- }
62
- };
63
- }
64
-
65
- /**
66
- * Get configuration file path
67
- */
68
- private getConfigPath(): string {
69
- return path.resolve(ConfigService.CONFIG_FILE);
70
- }
71
-
72
- /**
73
- * Read configuration from file with caching
74
- */
75
- public readConfig(): SVGConfig {
76
- if (this.cachedConfig) {
77
- return { ...this.cachedConfig };
78
- }
79
-
80
- try {
81
- const configData = FileSystem.readJSONSync(this.getConfigPath());
82
-
83
- if (Object.keys(configData).length === 0) {
84
- logger.debug('No configuration found, using defaults');
85
- this.cachedConfig = this.getDefaultConfig();
86
- return this.cachedConfig;
87
- }
88
-
89
- // Merge with defaults to ensure all required properties exist
90
- this.cachedConfig = {
91
- ...this.getDefaultConfig(),
92
- ...configData
93
- };
94
-
95
- logger.debug('Configuration loaded successfully');
96
- return this.cachedConfig!;
97
- } catch (error) {
98
- logger.warn('Failed to read configuration, using defaults:', error);
99
- this.cachedConfig = this.getDefaultConfig();
100
- return this.cachedConfig;
101
- }
102
- }
103
-
104
- /**
105
- * Write configuration to file
106
- */
107
- public writeConfig(config: SVGConfig): void {
108
- try {
109
- FileSystem.writeJSONSync(this.getConfigPath(), config, { spaces: 2 });
110
- this.cachedConfig = config; // Update cache
111
- logger.success('Configuration saved successfully');
112
- } catch (error) {
113
- logger.error('Failed to write configuration:', error);
114
- throw error;
115
- }
116
- }
117
-
118
- /**
119
- * Initialize configuration with defaults
120
- */
121
- public async initConfig(): Promise<void> {
122
- const configPath = this.getConfigPath();
123
-
124
- if (await FileSystem.exists(configPath)) {
125
- logger.warn('Config file already exists:', configPath);
126
- return;
127
- }
128
-
129
- const defaultConfig = this.getDefaultConfig();
130
- this.writeConfig(defaultConfig);
131
- logger.success('Configuration initialized with defaults');
132
- }
133
-
134
- /**
135
- * Set a specific configuration value
136
- */
137
- public setConfig(key: string, value: any): void {
138
- const config = this.readConfig();
139
-
140
- // Support nested key paths like 'styleRules.fill'
141
- const keys = key.split('.');
142
- let current: any = config;
143
-
144
- for (let i = 0; i < keys.length - 1; i++) {
145
- const k = keys[i];
146
- if (!(k in current)) {
147
- current[k] = {};
148
- }
149
- current = current[k];
150
- }
151
-
152
- const finalKey = keys[keys.length - 1];
153
- current[finalKey] = value;
154
-
155
- this.writeConfig(config);
156
- logger.success(`Configuration updated: ${key} = ${value}`);
157
- }
158
-
159
- /**
160
- * Get a specific configuration value
161
- */
162
- public getConfig(key?: string): any {
163
- const config = this.readConfig();
164
-
165
- if (!key) {
166
- return config;
167
- }
168
-
169
- // Support nested key paths
170
- const keys = key.split('.');
171
- let current: any = config;
172
-
173
- for (const k of keys) {
174
- if (!(k in current)) {
175
- return undefined;
176
- }
177
- current = current[k];
178
- }
179
-
180
- return current;
181
- }
182
-
183
- /**
184
- * Validate configuration
185
- */
186
- public validateConfig(config?: SVGConfig): { valid: boolean; errors: string[] } {
187
- const configToValidate = config || this.readConfig();
188
- const errors: string[] = [];
189
-
190
- // Required string fields
191
- const requiredStringFields = ['source', 'output', 'defaultFill'];
192
- for (const field of requiredStringFields) {
193
- if (!configToValidate[field as keyof SVGConfig] || typeof configToValidate[field as keyof SVGConfig] !== 'string') {
194
- errors.push(`${field} must be a non-empty string`);
195
- }
196
- }
197
-
198
- // Required numeric fields
199
- const requiredNumericFields = ['defaultWidth', 'defaultHeight'];
200
- for (const field of requiredNumericFields) {
201
- const value = configToValidate[field as keyof SVGConfig];
202
- if (typeof value !== 'number' || value <= 0) {
203
- errors.push(`${field} must be a positive number`);
204
- }
205
- }
206
-
207
- // Validate exclude array
208
- if (configToValidate.exclude && !Array.isArray(configToValidate.exclude)) {
209
- errors.push('exclude must be an array');
210
- }
211
-
212
- // Validate styleRules object
213
- if (configToValidate.styleRules && typeof configToValidate.styleRules !== 'object') {
214
- errors.push('styleRules must be an object');
215
- }
216
-
217
- return {
218
- valid: errors.length === 0,
219
- errors
220
- };
221
- }
222
-
223
- /**
224
- * Clear cached configuration (useful for testing)
225
- */
226
- public clearCache(): void {
227
- this.cachedConfig = null;
228
- }
229
-
230
- /**
231
- * Display current configuration
232
- */
233
- public showConfig(): void {
234
- const config = this.readConfig();
235
- console.log('📄 Current Configuration:');
236
- console.log(JSON.stringify(config, null, 2));
237
- }
238
- }
239
-
240
- // Export singleton instance
241
- export const configService = ConfigService.getInstance();