svgfusion 1.3.0 → 1.5.0

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/README.md CHANGED
@@ -28,9 +28,20 @@ A powerful Node.js CLI tool and library that converts SVG files into optimized R
28
28
  - **Batch Processing**: Convert entire directories of SVG files
29
29
  - **Production Ready**: Robust output with proper error handling
30
30
  - **Zero Configuration**: Works out of the box with sensible defaults
31
+ - **Simple CLI**: Direct, intuitive command structure without subcommands
31
32
 
32
33
  ## Quick Start
33
34
 
35
+ ### Simple as One Command
36
+
37
+ ```bash
38
+ # Convert all SVG files in a directory to React components
39
+ npx svgfusion ./icons --output ./components
40
+
41
+ # Add prefixes, suffixes, and generate index file
42
+ npx svgfusion ./icons --prefix Icon --suffix Component --index
43
+ ```
44
+
34
45
  ### Installation
35
46
 
36
47
  ```bash
@@ -38,12 +49,9 @@ A powerful Node.js CLI tool and library that converts SVG files into optimized R
38
49
  npm install -g svgfusion
39
50
 
40
51
  # Or use npx (no installation needed)
41
- npx svgfusion convert ./icons --output ./components
52
+ npx svgfusion ./icons --output ./components
42
53
 
43
54
  # Or install locally for programmatic usage
44
-
45
- # Add prefix and suffix to component names
46
- svgfusion convert ./icons --output ./components --prefix Icon --suffix Svg
47
55
  npm install svgfusion
48
56
  # or
49
57
  yarn add svgfusion
@@ -53,12 +61,14 @@ pnpm add svgfusion
53
61
 
54
62
  ## CLI Options
55
63
 
56
- svgfusion convert ./icons --output ./components --prefix Icon --suffix Svg
64
+ <img src="https://i.ibb.co/8n2b5mtp/cli.png" alt="SVGFusion CLI" width="512" >
65
+
66
+ svgfusion ./icons --output ./components --prefix Icon --suffix Svg
57
67
 
58
68
  You can add a prefix and/or suffix to the generated component names using the `--prefix` and `--suffix` options:
59
69
 
60
70
  ```sh
61
- npx svgfusion convert ./svgs --prefix Icon --suffix Svg
71
+ npx svgfusion ./svgs --prefix Icon --suffix Svg
62
72
  ```
63
73
 
64
74
  This will generate components like `IconStarSvg`, `IconUserSvg`, etc.
@@ -68,7 +78,7 @@ Both options sanitize input to remove symbols and spaces. If omitted, no prefix/
68
78
  #### Example
69
79
 
70
80
  ```sh
71
- npx svgfusion convert ./svgs --prefix App --suffix Widget
81
+ npx svgfusion ./svgs --prefix App --suffix Widget
72
82
  # Output: AppStarWidget, AppUserWidget, ...
73
83
  ```
74
84
 
@@ -82,30 +92,40 @@ npx svgfusion --help
82
92
 
83
93
  ```bash
84
94
  # Convert to React components (default)
85
- svgfusion convert ./icons --output ./components
95
+ svgfusion ./icons --output ./components
86
96
 
87
97
  # Convert to Vue 3 components
88
- svgfusion convert ./icons --output ./components --framework vue
98
+ svgfusion ./icons --output ./components --framework vue
89
99
 
90
100
  # Single file conversion with TypeScript
91
- svgfusion convert ./star.svg --output ./components --typescript
101
+ svgfusion ./star.svg --output ./components --typescript
102
+
103
+ # Batch processing with recursive directory scanning
104
+ svgfusion ./icons --output ./components --recursive
105
+
106
+ # Generate index file for tree-shaking
107
+ svgfusion ./icons --output ./components --index
92
108
 
93
109
  # Skip optimization
94
- svgfusion convert ./icons --output ./components --no-optimize
110
+ svgfusion ./icons --output ./components --no-optimize
95
111
 
96
112
  # Using npx (no global install needed)
97
- npx svgfusion convert ./icons --output ./components --framework react
113
+ npx svgfusion ./icons --output ./components --framework react
98
114
  ```
99
115
 
100
116
  ### CLI Options
101
117
 
102
118
  ```bash
103
- svgfusion convert <input> [options]
119
+ svgfusion <input> [options]
104
120
 
105
121
  Options:
106
122
  -o, --output <output> Output directory (default: "./components")
107
123
  -f, --framework <framework> Target framework (react|vue) (default: "react")
108
124
  -t, --typescript Generate TypeScript files
125
+ -r, --recursive Recursively scan input directory for SVG files
126
+ --index Generate index file for tree-shaking
127
+ --index-format <format> Index file format (ts|js) (default: "ts")
128
+ --export-type <type> Export type (named|default) (default: "named")
109
129
  --no-optimize Skip SVG optimization
110
130
  --prefix <prefix> Add prefix to component name (sanitized)
111
131
  --suffix <suffix> Add suffix to component name (sanitized)
@@ -118,17 +138,25 @@ Perfect for trying out SVGFusion or one-time conversions:
118
138
 
119
139
  ```bash
120
140
  # Convert React components
121
- npx svgfusion convert ./assets/icons --output ./src/components/icons
141
+ npx svgfusion ./assets/icons --output ./src/components/icons
122
142
 
123
143
  # Convert Vue components with TypeScript
124
- npx svgfusion convert ./assets/icons --output ./src/components --framework vue --typescript
144
+ npx svgfusion ./assets/icons --output ./src/components --framework vue --typescript
125
145
 
126
146
  # Convert single file
127
- npx svgfusion convert ./logo.svg --output ./src/components --framework react
147
+ npx svgfusion ./logo.svg --output ./src/components --framework react
148
+
149
+ # Batch convert with index generation
150
+ npx svgfusion ./assets/icons --output ./src/components --recursive --index
151
+
152
+ # Convert with custom naming
153
+ npx svgfusion ./assets/icons --output ./src/components --prefix Icon --suffix Component --index
128
154
  ```
129
155
 
130
156
  ### Programmatic Usage
131
157
 
158
+ #### Single File Conversion
159
+
132
160
  ```typescript
133
161
  import { convertToReact, convertToVue, readSvgFile } from 'svgfusion';
134
162
 
@@ -154,6 +182,41 @@ console.log(reactResult.code); // Generated React component
154
182
  console.log(vueResult.code); // Generated Vue component
155
183
  ```
156
184
 
185
+ #### Batch Processing
186
+
187
+ ```typescript
188
+ import { BatchConverter } from 'svgfusion';
189
+
190
+ const batchConverter = new BatchConverter();
191
+
192
+ // Convert entire directory
193
+ const result = await batchConverter.convertBatch({
194
+ inputDir: './icons',
195
+ outputDir: './components',
196
+ framework: 'react',
197
+ recursive: true,
198
+ generateIndex: true,
199
+ typescript: true,
200
+ prefix: 'Icon',
201
+ suffix: 'Component',
202
+ indexFormat: 'ts',
203
+ exportType: 'named',
204
+ });
205
+
206
+ // Check results
207
+ console.log(`Processed ${result.summary.total} files`);
208
+ console.log(`Successful: ${result.summary.successful}`);
209
+ console.log(`Failed: ${result.summary.failed}`);
210
+
211
+ // Get component names
212
+ const componentNames = batchConverter.getComponentNames(result);
213
+ console.log('Generated components:', componentNames);
214
+
215
+ // Generate summary report
216
+ const report = batchConverter.generateSummaryReport(result);
217
+ console.log(report);
218
+ ```
219
+
157
220
  ## API Reference
158
221
 
159
222
  ### `convertToReact(svgContent, options)`
@@ -184,6 +247,39 @@ Convert SVG to Vue 3 component. **Note: This is a synchronous function.**
184
247
  - `compositionApi?: boolean` - Use Composition API (default: `true`)
185
248
  - `optimize?: boolean` - Apply SVGO optimization (default: `true`)
186
249
 
250
+ ### `BatchConverter`
251
+
252
+ Process multiple SVG files in batch operations.
253
+
254
+ #### `convertBatch(options: BatchConversionOptions)`
255
+
256
+ Convert multiple SVG files to framework components.
257
+
258
+ **Options:**
259
+
260
+ - `inputDir: string` - Input directory path
261
+ - `outputDir: string` - Output directory path
262
+ - `framework?: 'react' | 'vue'` - Target framework (default: 'react')
263
+ - `recursive?: boolean` - Recursively scan directories (default: false)
264
+ - `extensions?: string[]` - File extensions to process (default: ['.svg'])
265
+ - `generateIndex?: boolean` - Generate index file (default: false)
266
+ - `indexFormat?: 'ts' | 'js'` - Index file format (default: 'ts')
267
+ - `exportType?: 'named' | 'default'` - Export type (default: 'named')
268
+ - `prefix?: string` - Add prefix to component names
269
+ - `suffix?: string` - Add suffix to component names
270
+ - `typescript?: boolean` - Generate TypeScript components (default: true)
271
+ - All other conversion options from `convertToReact`/`convertToVue`
272
+
273
+ **Returns:** `Promise<BatchConversionResult>`
274
+
275
+ #### `getComponentNames(results: BatchConversionResult)`
276
+
277
+ Get array of generated component names from batch results.
278
+
279
+ #### `generateSummaryReport(results: BatchConversionResult)`
280
+
281
+ Generate a detailed summary report of the conversion process.
282
+
187
283
  ### `optimizeSvg(svgContent, config?)`
188
284
 
189
285
  Optimize SVG content using SVGO. **Note: This is a synchronous function.**
@@ -284,7 +380,7 @@ const customConfig = createSvgoConfig({
284
380
  const optimizedSvg = optimizeSvg(svgContent, customConfig);
285
381
  ```
286
382
 
287
- ### Batch Processing
383
+ ### Manual Batch Processing
288
384
 
289
385
  ```typescript
290
386
  import {
@@ -306,6 +402,65 @@ for (const svgFile of svgFiles) {
306
402
  }
307
403
  ```
308
404
 
405
+ ### Index File Generation
406
+
407
+ When using the `--index` flag or `generateIndex: true` option, SVGFusion creates an optimized index file for tree-shaking:
408
+
409
+ #### Named Exports (Default)
410
+
411
+ ```typescript
412
+ // Auto-generated index file for tree-shaking
413
+ // This file exports all components for optimal bundling
414
+
415
+ export { default as IconStar } from './IconStar';
416
+ export { default as IconUser } from './IconUser';
417
+ export { default as IconHome } from './IconHome';
418
+
419
+ // Barrel export for convenience
420
+ export { IconStar, IconUser, IconHome };
421
+
422
+ // TypeScript component types
423
+ export type IconComponent = React.ComponentType<React.SVGProps<SVGSVGElement>>;
424
+ export type IconComponents = {
425
+ IconStar: IconComponent;
426
+ IconUser: IconComponent;
427
+ IconHome: IconComponent;
428
+ };
429
+ ```
430
+
431
+ #### Default Exports
432
+
433
+ ```typescript
434
+ // Auto-generated index file
435
+ // Warning: Default exports are less tree-shakeable
436
+
437
+ import IconStar from './IconStar';
438
+ import IconUser from './IconUser';
439
+ import IconHome from './IconHome';
440
+
441
+ export default {
442
+ IconStar,
443
+ IconUser,
444
+ IconHome,
445
+ };
446
+
447
+ // Individual exports for flexibility
448
+ export { default as IconStar } from './IconStar';
449
+ export { default as IconUser } from './IconUser';
450
+ export { default as IconHome } from './IconHome';
451
+ ```
452
+
453
+ #### Usage
454
+
455
+ ```typescript
456
+ // Tree-shakeable named imports (recommended)
457
+ import { IconStar, IconUser } from './components';
458
+
459
+ // Default import
460
+ import * as Icons from './components';
461
+ const { IconStar, IconUser } = Icons;
462
+ ```
463
+
309
464
  ## Complex Filename Support
310
465
 
311
466
  SVGFusion handles complex filenames from design systems:
package/dist/cli.js CHANGED
@@ -44,6 +44,7 @@ var init_cjs_shims = __esm({
44
44
  // src/utils/files.ts
45
45
  var files_exports = {};
46
46
  __export(files_exports, {
47
+ ensureDir: () => ensureDir,
47
48
  ensureDirectoryExists: () => ensureDirectoryExists,
48
49
  getComponentFilename: () => getComponentFilename,
49
50
  getFileExtension: () => getFileExtension,
@@ -110,7 +111,7 @@ function getFileExtension(framework, typescript = true) {
110
111
  function getComponentFilename(_svgFilename, componentName, extension) {
111
112
  return `${componentName}${extension}`;
112
113
  }
113
- var import_promises, import_path, import_fs;
114
+ var import_promises, import_path, import_fs, ensureDir;
114
115
  var init_files = __esm({
115
116
  "src/utils/files.ts"() {
116
117
  "use strict";
@@ -118,6 +119,151 @@ var init_files = __esm({
118
119
  import_promises = require("fs/promises");
119
120
  import_path = require("path");
120
121
  import_fs = require("fs");
122
+ ensureDir = ensureDirectoryExists;
123
+ }
124
+ });
125
+
126
+ // src/utils/index-generator.ts
127
+ var index_generator_exports = {};
128
+ __export(index_generator_exports, {
129
+ generateIndexFile: () => generateIndexFile,
130
+ generateReadmeContent: () => generateReadmeContent
131
+ });
132
+ function generateIndexFile(results, options) {
133
+ const { format, exportType, typescript } = options;
134
+ const sortedResults = [...results].sort(
135
+ (a, b) => a.componentName.localeCompare(b.componentName)
136
+ );
137
+ if (exportType === "default") {
138
+ return generateDefaultExports(sortedResults, format, typescript);
139
+ } else {
140
+ return generateNamedExports(sortedResults, format, typescript);
141
+ }
142
+ }
143
+ function generateNamedExports(results, format, typescript) {
144
+ let content = "";
145
+ content += `// Auto-generated index file for tree-shaking
146
+ `;
147
+ content += `// This file exports all components for optimal bundling
148
+
149
+ `;
150
+ for (const result of results) {
151
+ const importPath = getImportPath(result.filename);
152
+ content += `export { default as ${result.componentName} } from './${importPath}';
153
+ `;
154
+ }
155
+ content += `
156
+ // Barrel export for convenience
157
+ `;
158
+ content += `export {
159
+ `;
160
+ for (const result of results) {
161
+ content += ` ${result.componentName},
162
+ `;
163
+ }
164
+ content += `};
165
+ `;
166
+ if (typescript && format === "ts") {
167
+ content += `
168
+ // TypeScript component types
169
+ `;
170
+ content += `export type IconComponent = React.ComponentType<React.SVGProps<SVGSVGElement>>;
171
+ `;
172
+ content += `export type IconComponents = {
173
+ `;
174
+ for (const result of results) {
175
+ content += ` ${result.componentName}: IconComponent;
176
+ `;
177
+ }
178
+ content += `};
179
+ `;
180
+ }
181
+ return content;
182
+ }
183
+ function generateDefaultExports(results, _format, _typescript) {
184
+ let content = "";
185
+ content += `// Auto-generated index file
186
+ `;
187
+ content += `// Warning: Default exports are less tree-shakeable
188
+
189
+ `;
190
+ for (const result of results) {
191
+ const importPath = getImportPath(result.filename);
192
+ content += `import ${result.componentName} from './${importPath}';
193
+ `;
194
+ }
195
+ content += `
196
+ export default {
197
+ `;
198
+ for (const result of results) {
199
+ content += ` ${result.componentName},
200
+ `;
201
+ }
202
+ content += `};
203
+ `;
204
+ content += `
205
+ // Individual exports for flexibility
206
+ `;
207
+ for (const result of results) {
208
+ content += `export { default as ${result.componentName} } from './${getImportPath(result.filename)}';
209
+ `;
210
+ }
211
+ return content;
212
+ }
213
+ function getImportPath(filename) {
214
+ return filename.replace(/\.(tsx?|jsx?|vue)$/, "");
215
+ }
216
+ function generateReadmeContent(results) {
217
+ const componentNames = results.map((r) => r.componentName).sort();
218
+ let content = `# Generated Components
219
+
220
+ `;
221
+ content += `This directory contains ${results.length} auto-generated components from SVG files.
222
+
223
+ `;
224
+ content += `## Usage
225
+
226
+ `;
227
+ content += `### Named imports (recommended for tree-shaking)
228
+
229
+ `;
230
+ content += `\`\`\`typescript
231
+ `;
232
+ content += `import { ${componentNames.slice(0, 3).join(", ")} } from './index';
233
+ `;
234
+ content += `\`\`\`
235
+
236
+ `;
237
+ content += `### Default import
238
+
239
+ `;
240
+ content += `\`\`\`typescript
241
+ `;
242
+ content += `import * as Icons from './index';
243
+ `;
244
+ content += `\`\`\`
245
+
246
+ `;
247
+ content += `## Available Components
248
+
249
+ `;
250
+ for (const name of componentNames) {
251
+ content += `- \`${name}\`
252
+ `;
253
+ }
254
+ content += `
255
+ ## Tree-shaking
256
+
257
+ `;
258
+ content += `This index file is optimized for tree-shaking. When using named imports, `;
259
+ content += `bundlers like webpack, Rollup, or Vite will only include the components you actually use.
260
+ `;
261
+ return content;
262
+ }
263
+ var init_index_generator = __esm({
264
+ "src/utils/index-generator.ts"() {
265
+ "use strict";
266
+ init_cjs_shims();
121
267
  }
122
268
  });
123
269
 
@@ -130,11 +276,20 @@ var import_path2 = require("path");
130
276
 
131
277
  // src/utils/name.ts
132
278
  init_cjs_shims();
133
- var import_just_pascal_case = __toESM(require("just-pascal-case"));
279
+
280
+ // src/utils/string.ts
281
+ init_cjs_shims();
282
+ var pascalCase = (str) => {
283
+ return str.match(
284
+ /[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*[a-z]*|[A-Z]|[0-9]+[a-z]*/g
285
+ )?.map((x) => x.charAt(0).toUpperCase() + x.slice(1).toLowerCase()).join("") || "";
286
+ };
287
+
288
+ // src/utils/name.ts
134
289
  function svgToComponentName(filename) {
135
290
  let baseName = filename.replace(/\.svg$/i, "");
136
291
  baseName = processComplexFilename(baseName);
137
- return (0, import_just_pascal_case.default)(baseName);
292
+ return pascalCase(baseName);
138
293
  }
139
294
  function processComplexFilename(filename) {
140
295
  let processed = filename.toLowerCase().replace(/[^a-zA-Z0-9]/g, " ");
@@ -142,9 +297,9 @@ function processComplexFilename(filename) {
142
297
  return processed;
143
298
  }
144
299
  function formatComponentName(name, prefix, suffix) {
145
- const prefixPart = prefix ? (0, import_just_pascal_case.default)(prefix) : "";
146
- const suffixPart = suffix ? (0, import_just_pascal_case.default)(suffix) : "";
147
- const baseName = (0, import_just_pascal_case.default)(name);
300
+ const prefixPart = prefix ? pascalCase(prefix) : "";
301
+ const suffixPart = suffix ? pascalCase(suffix) : "";
302
+ const baseName = pascalCase(name);
148
303
  return `${prefixPart}${baseName}${suffixPart}`;
149
304
  }
150
305
 
@@ -477,11 +632,7 @@ export default {
477
632
  <template>
478
633
  ${svg}
479
634
  </template>`;
480
- const style = `
481
- <style scoped>
482
- /* Component styles */
483
- </style>`;
484
- return [script, template, style].filter(Boolean).join("\n");
635
+ return [script, template].filter(Boolean).join("\n");
485
636
  }
486
637
 
487
638
  // src/core/vue-converter.ts
@@ -520,43 +671,11 @@ async function convertToVue(svgContent, options = {}) {
520
671
  var import_url = require("url");
521
672
  var import_path3 = require("path");
522
673
  var import_fs2 = require("fs");
674
+
675
+ // src/utils/banner.ts
676
+ init_cjs_shims();
523
677
  var import_figlet = __toESM(require("figlet"));
524
- var colors = {
525
- cyan: "\x1B[36m",
526
- blue: "\x1B[34m",
527
- green: "\x1B[32m",
528
- red: "\x1B[31m",
529
- gray: "\x1B[90m",
530
- dim: "\x1B[2m",
531
- // Bold gradient colors with dramatic artistic accents
532
- darkBlue: "\x1B[38;2;0;100;255m",
533
- // Electric blue (bold)
534
- mediumBlue: "\x1B[38;2;50;150;255m",
535
- // Bright blue
536
- lightBlue: "\x1B[38;2;100;200;255m",
537
- // Vivid sky blue
538
- blueCyan: "\x1B[38;2;0;150;255m",
539
- // Electric blue-cyan
540
- mediumCyan: "\x1B[38;2;0;255;255m",
541
- // Pure cyan (bold)
542
- darkCyan: "\x1B[38;2;0;200;200m",
543
- // Electric turquoise
544
- softTeal: "\x1B[38;2;0;255;150m",
545
- // Electric teal
546
- tealGreen: "\x1B[38;2;0;200;100m",
547
- // Vivid teal green
548
- softGreen: "\x1B[38;2;50;255;100m",
549
- // Electric green
550
- mediumGreen: "\x1B[38;2;0;255;50m",
551
- // Pure green (bold)
552
- reset: "\x1B[0m"
553
- };
554
- var __filename2 = (0, import_url.fileURLToPath)(importMetaUrl);
555
- var __dirname = (0, import_path3.dirname)(__filename2);
556
- var packageJson = JSON.parse(
557
- (0, import_fs2.readFileSync)((0, import_path3.join)(__dirname, "..", "package.json"), "utf-8")
558
- );
559
- function createBanner() {
678
+ function createBanner(colors2) {
560
679
  const title = import_figlet.default.textSync("SVGfusion", {
561
680
  font: "ANSI Shadow",
562
681
  horizontalLayout: "default",
@@ -576,25 +695,25 @@ function createBanner() {
576
695
  return char;
577
696
  }
578
697
  if (diagonalProgress <= 0.1) {
579
- return `${colors.darkBlue}${char}${colors.reset}`;
698
+ return `${colors2.darkBlue}${char}${colors2.reset}`;
580
699
  } else if (diagonalProgress <= 0.2) {
581
- return `${colors.lightBlue}${char}${colors.reset}`;
700
+ return `${colors2.lightBlue}${char}${colors2.reset}`;
582
701
  } else if (diagonalProgress <= 0.32) {
583
- return `${colors.mediumBlue}${char}${colors.reset}`;
702
+ return `${colors2.mediumBlue}${char}${colors2.reset}`;
584
703
  } else if (diagonalProgress <= 0.42) {
585
- return `${colors.blueCyan}${char}${colors.reset}`;
704
+ return `${colors2.blueCyan}${char}${colors2.reset}`;
586
705
  } else if (diagonalProgress <= 0.52) {
587
- return `${colors.mediumCyan}${char}${colors.reset}`;
706
+ return `${colors2.mediumCyan}${char}${colors2.reset}`;
588
707
  } else if (diagonalProgress <= 0.62) {
589
- return `${colors.darkCyan}${char}${colors.reset}`;
708
+ return `${colors2.darkCyan}${char}${colors2.reset}`;
590
709
  } else if (diagonalProgress <= 0.72) {
591
- return `${colors.softTeal}${char}${colors.reset}`;
710
+ return `${colors2.softTeal}${char}${colors2.reset}`;
592
711
  } else if (diagonalProgress <= 0.82) {
593
- return `${colors.tealGreen}${char}${colors.reset}`;
712
+ return `${colors2.tealGreen}${char}${colors2.reset}`;
594
713
  } else if (diagonalProgress <= 0.92) {
595
- return `${colors.softGreen}${char}${colors.reset}`;
714
+ return `${colors2.softGreen}${char}${colors2.reset}`;
596
715
  } else {
597
- return `${colors.mediumGreen}${char}${colors.reset}`;
716
+ return `${colors2.mediumGreen}${char}${colors2.reset}`;
598
717
  }
599
718
  }).join("");
600
719
  return processedLine;
@@ -602,30 +721,89 @@ function createBanner() {
602
721
  return `
603
722
  ${gradientTitle}
604
723
 
605
- ${colors.gray}Transform SVG files into production-ready components${colors.reset}
606
- ${colors.blue}React${colors.reset} ${colors.gray}\u2022${colors.reset} ${colors.green}Vue 3${colors.reset} ${colors.gray}\u2022${colors.reset} ${colors.blue}TypeScript${colors.reset}
724
+ ${colors2.gray}Transform SVG files into production-ready components${colors2.reset}
725
+ ${colors2.blue}React${colors2.reset} ${colors2.gray}\u2022${colors2.reset} ${colors2.green}Vue 3${colors2.reset} ${colors2.gray}\u2022${colors2.reset} ${colors2.blue}TypeScript${colors2.reset}
607
726
 
608
- ${colors.gray}\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500${colors.reset}
727
+ ${colors2.gray}\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500${colors2.reset}
609
728
  `;
610
729
  }
730
+
731
+ // src/utils/colors.ts
732
+ init_cjs_shims();
733
+ var colors = {
734
+ cyan: "\x1B[36m",
735
+ blue: "\x1B[34m",
736
+ green: "\x1B[32m",
737
+ red: "\x1B[31m",
738
+ gray: "\x1B[90m",
739
+ dim: "\x1B[2m",
740
+ // Bold gradient colors with dramatic artistic accents
741
+ darkBlue: "\x1B[38;2;0;100;255m",
742
+ // Electric blue (bold)
743
+ mediumBlue: "\x1B[38;2;50;150;255m",
744
+ // Bright blue
745
+ lightBlue: "\x1B[38;2;100;200;255m",
746
+ // Vivid sky blue
747
+ blueCyan: "\x1B[38;2;0;150;255m",
748
+ // Electric blue-cyan
749
+ mediumCyan: "\x1B[38;2;0;255;255m",
750
+ // Pure cyan (bold)
751
+ darkCyan: "\x1B[38;2;0;200;200m",
752
+ // Electric turquoise
753
+ softTeal: "\x1B[38;2;0;255;150m",
754
+ // Electric teal
755
+ tealGreen: "\x1B[38;2;0;200;100m",
756
+ // Vivid teal green
757
+ softGreen: "\x1B[38;2;50;255;100m",
758
+ // Electric green
759
+ mediumGreen: "\x1B[38;2;0;255;50m",
760
+ // Pure green (bold)
761
+ reset: "\x1B[0m"
762
+ };
763
+
764
+ // src/cli.ts
765
+ var __filename2 = (0, import_url.fileURLToPath)(importMetaUrl);
766
+ var __dirname = (0, import_path3.dirname)(__filename2);
767
+ var packageJson = JSON.parse(
768
+ (0, import_fs2.readFileSync)((0, import_path3.join)(__dirname, "..", "package.json"), "utf-8")
769
+ );
611
770
  var program = new import_commander.Command();
612
771
  var isNpxCall = process.argv[1]?.includes("npx") || process.argv[1]?.includes("_npx");
613
- if (process.argv.length === 2 || isNpxCall && process.argv.length === 3) {
614
- console.log(createBanner());
772
+ if (process.argv.length === 1 || isNpxCall && process.argv.length === 2) {
773
+ console.log(createBanner(colors));
615
774
  }
616
775
  program.name("svgfusion").description(
617
776
  "Transform SVG files into production-ready React and Vue 3 components"
618
777
  ).version(packageJson.version);
619
- program.command("convert").description("Convert SVG files to React or Vue components").argument("<input>", "Input SVG file or directory").option("-o, --output <output>", "Output directory", "./components").option(
778
+ program.argument("[input]", "Input SVG file or directory").option("-o, --output <output>", "Output directory", "./components").option(
620
779
  "-f, --framework <framework>",
621
780
  "Target framework (react|vue)",
622
781
  "react"
623
- ).option("-t, --typescript", "Generate TypeScript files", false).option("--no-optimize", "Skip SVG optimization").option("--prefix <prefix>", "Add prefix to component name").option("--suffix <suffix>", "Add suffix to component name").action(
782
+ ).option("-t, --typescript", "Generate TypeScript files", false).option(
783
+ "-r, --recursive",
784
+ "Recursively scan input directory for SVG files",
785
+ false
786
+ ).option("--no-optimize", "Skip SVG optimization").option("--prefix <prefix>", "Add prefix to component name").option("--suffix <suffix>", "Add suffix to component name").option("--index", "Generate index file for tree-shaking", false).option("--index-format <format>", "Index file format (ts|js)", "ts").option("--export-type <type>", "Export type (named|default)", "named").action(
624
787
  async (input, options) => {
625
- console.log(createBanner());
788
+ if (!input) {
789
+ program.outputHelp();
790
+ process.exit(0);
791
+ }
792
+ console.log(createBanner(colors));
626
793
  console.log(`${colors.blue}\u{1F504} Processing SVG files...${colors.reset}`);
627
794
  try {
628
- const { framework, output, typescript, optimize: optimize2, prefix, suffix } = options;
795
+ const {
796
+ framework,
797
+ output,
798
+ typescript,
799
+ recursive,
800
+ optimize: optimize2,
801
+ prefix,
802
+ suffix,
803
+ index: generateIndex,
804
+ indexFormat,
805
+ exportType
806
+ } = options;
629
807
  if (framework !== "react" && framework !== "vue") {
630
808
  throw new Error('Framework must be either "react" or "vue"');
631
809
  }
@@ -638,7 +816,7 @@ program.command("convert").description("Convert SVG files to React or Vue compon
638
816
  throw new Error("Input file must be an SVG file");
639
817
  }
640
818
  } else if (inputStat.isDirectory()) {
641
- svgFiles = await readSvgDirectory(input);
819
+ svgFiles = await readSvgDirectory(input, recursive);
642
820
  } else {
643
821
  throw new Error("Input must be a file or directory");
644
822
  }
@@ -648,6 +826,7 @@ program.command("convert").description("Convert SVG files to React or Vue compon
648
826
  console.log(
649
827
  `${colors.blue}\u{1F504} Converting ${svgFiles.length} SVG file(s)...${colors.reset}`
650
828
  );
829
+ const results = [];
651
830
  for (const filePath of svgFiles) {
652
831
  const svgContent = await readSvgFile(filePath);
653
832
  const optimizedSvg = optimize2 ? optimizeSvg(svgContent) : svgContent;
@@ -666,6 +845,21 @@ program.command("convert").description("Convert SVG files to React or Vue compon
666
845
  });
667
846
  const outputPath = (0, import_path3.join)(output, result.filename);
668
847
  await writeComponentFile(outputPath, result.code);
848
+ results.push(result);
849
+ }
850
+ if (generateIndex && results.length > 0) {
851
+ const { generateIndexFile: generateIndexFile2 } = await Promise.resolve().then(() => (init_index_generator(), index_generator_exports));
852
+ const indexContent = generateIndexFile2(results, {
853
+ format: indexFormat,
854
+ exportType,
855
+ typescript
856
+ });
857
+ const indexFilename = `index.${indexFormat}`;
858
+ const indexPath = (0, import_path3.join)(output, indexFilename);
859
+ await writeComponentFile(indexPath, indexContent);
860
+ console.log(
861
+ `${colors.green}\u{1F4C4} Generated ${indexFilename} for tree-shaking${colors.reset}`
862
+ );
669
863
  }
670
864
  console.log(
671
865
  `${colors.green}\u2705 Successfully converted ${svgFiles.length} SVG file(s) to ${framework} components${colors.reset}`
@@ -673,6 +867,10 @@ program.command("convert").description("Convert SVG files to React or Vue compon
673
867
  console.log(
674
868
  `${colors.dim}\u{1F4C1} Output location: ${colors.reset}${colors.cyan}${output}${colors.reset}`
675
869
  );
870
+ const componentNames = results.map((r) => r.componentName);
871
+ console.log(
872
+ `${colors.dim}\u{1F4E6} Generated components: ${colors.reset}${componentNames.join(", ")}`
873
+ );
676
874
  } catch (error) {
677
875
  console.error(
678
876
  `${colors.red}\u274C Error: ${error instanceof Error ? error.message : "Unknown error"}${colors.reset}`
@@ -680,5 +878,19 @@ program.command("convert").description("Convert SVG files to React or Vue compon
680
878
  process.exit(1);
681
879
  }
682
880
  }
881
+ ).addHelpText("before", createBanner(colors)).addHelpText(
882
+ "after",
883
+ `
884
+ ${colors.gray}Examples:${colors.reset}
885
+ ${colors.blue}svgfusion src/icons -o src/components${colors.reset}
886
+ ${colors.blue}svgfusion src/icons --framework vue --typescript${colors.reset}
887
+ ${colors.blue}svgfusion src/icons --recursive --index${colors.reset}
888
+ ${colors.blue}svgfusion src/icons --prefix Icon --suffix Component --index${colors.reset}
889
+ ${colors.blue}svgfusion src/icons --framework react --typescript --optimize${colors.reset}
890
+ `
683
891
  );
892
+ if (process.argv.length === 2) {
893
+ program.outputHelp();
894
+ process.exit(0);
895
+ }
684
896
  program.parse();
package/dist/index.d.mts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { Config } from 'svgo';
2
- export { default as pascalCase } from 'just-pascal-case';
3
2
 
4
3
  interface ConversionOptions {
5
4
  name?: string;
@@ -41,6 +40,10 @@ interface BatchConversionOptions extends ConversionOptions {
41
40
  outputDir: string;
42
41
  recursive?: boolean;
43
42
  extensions?: string[];
43
+ generateIndex?: boolean;
44
+ indexFormat?: 'ts' | 'js';
45
+ exportType?: 'named' | 'default';
46
+ framework?: Framework;
44
47
  }
45
48
  interface BatchConversionResult {
46
49
  results: ConversionResult[];
@@ -69,6 +72,9 @@ interface CliOptions {
69
72
  format?: 'esm' | 'cjs';
70
73
  recursive?: boolean;
71
74
  verbose?: boolean;
75
+ generateIndex?: boolean;
76
+ indexFormat?: 'ts' | 'js';
77
+ exportType?: 'named' | 'default';
72
78
  }
73
79
 
74
80
  /**
@@ -129,6 +135,8 @@ declare function writeComponentFile(filePath: string, content: string): Promise<
129
135
  */
130
136
  declare function readSvgDirectory(dirPath: string, recursive?: boolean): Promise<string[]>;
131
137
 
138
+ declare const pascalCase: (str: string) => string;
139
+
132
140
  /**
133
141
  * Convert SVG filename to a valid React component name
134
142
  * @param filename - The SVG filename
@@ -151,4 +159,4 @@ declare function sanitizeComponentName(name: string): string;
151
159
  */
152
160
  declare function formatComponentName(name: string, prefix?: string, suffix?: string): string;
153
161
 
154
- export { type BatchConversionOptions, type BatchConversionResult, type CliOptions, type ConversionError, type ConversionOptions, type ConversionResult, type Framework, type ReactConversionOptions, type VueConversionOptions, convertToReact, convertToVue, createSvgoConfig, formatComponentName, optimizeSvg, readSvgDirectory, readSvgFile, sanitizeComponentName, svgToComponentName, writeComponentFile, writeSvgFile };
162
+ export { type BatchConversionOptions, type BatchConversionResult, type CliOptions, type ConversionError, type ConversionOptions, type ConversionResult, type Framework, type ReactConversionOptions, type VueConversionOptions, convertToReact, convertToVue, createSvgoConfig, formatComponentName, optimizeSvg, pascalCase, readSvgDirectory, readSvgFile, sanitizeComponentName, svgToComponentName, writeComponentFile, writeSvgFile };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { Config } from 'svgo';
2
- export { default as pascalCase } from 'just-pascal-case';
3
2
 
4
3
  interface ConversionOptions {
5
4
  name?: string;
@@ -41,6 +40,10 @@ interface BatchConversionOptions extends ConversionOptions {
41
40
  outputDir: string;
42
41
  recursive?: boolean;
43
42
  extensions?: string[];
43
+ generateIndex?: boolean;
44
+ indexFormat?: 'ts' | 'js';
45
+ exportType?: 'named' | 'default';
46
+ framework?: Framework;
44
47
  }
45
48
  interface BatchConversionResult {
46
49
  results: ConversionResult[];
@@ -69,6 +72,9 @@ interface CliOptions {
69
72
  format?: 'esm' | 'cjs';
70
73
  recursive?: boolean;
71
74
  verbose?: boolean;
75
+ generateIndex?: boolean;
76
+ indexFormat?: 'ts' | 'js';
77
+ exportType?: 'named' | 'default';
72
78
  }
73
79
 
74
80
  /**
@@ -129,6 +135,8 @@ declare function writeComponentFile(filePath: string, content: string): Promise<
129
135
  */
130
136
  declare function readSvgDirectory(dirPath: string, recursive?: boolean): Promise<string[]>;
131
137
 
138
+ declare const pascalCase: (str: string) => string;
139
+
132
140
  /**
133
141
  * Convert SVG filename to a valid React component name
134
142
  * @param filename - The SVG filename
@@ -151,4 +159,4 @@ declare function sanitizeComponentName(name: string): string;
151
159
  */
152
160
  declare function formatComponentName(name: string, prefix?: string, suffix?: string): string;
153
161
 
154
- export { type BatchConversionOptions, type BatchConversionResult, type CliOptions, type ConversionError, type ConversionOptions, type ConversionResult, type Framework, type ReactConversionOptions, type VueConversionOptions, convertToReact, convertToVue, createSvgoConfig, formatComponentName, optimizeSvg, readSvgDirectory, readSvgFile, sanitizeComponentName, svgToComponentName, writeComponentFile, writeSvgFile };
162
+ export { type BatchConversionOptions, type BatchConversionResult, type CliOptions, type ConversionError, type ConversionOptions, type ConversionResult, type Framework, type ReactConversionOptions, type VueConversionOptions, convertToReact, convertToVue, createSvgoConfig, formatComponentName, optimizeSvg, pascalCase, readSvgDirectory, readSvgFile, sanitizeComponentName, svgToComponentName, writeComponentFile, writeSvgFile };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- 'use strict';var promises=require('fs/promises'),path=require('path'),fs=require('fs'),core=require('@svgr/core'),svgo=require('svgo'),u=require('just-pascal-case');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var u__default=/*#__PURE__*/_interopDefault(u);var d=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var k=Object.prototype.hasOwnProperty;var R=(e,r)=>()=>(e&&(r=e(e=0)),r);var q=(e,r)=>{for(var t in r)d(e,t,{get:r[t],enumerable:true});},_=(e,r,t,o)=>{if(r&&typeof r=="object"||typeof r=="function")for(let n of L(r))!k.call(e,n)&&n!==t&&d(e,n,{get:()=>r[n],enumerable:!(o=I(r,n))||o.enumerable});return e};var M=e=>_(d({},"__esModule",{value:true}),e);var i=R(()=>{});var U={};q(U,{ensureDirectoryExists:()=>h,getComponentFilename:()=>ie,getFileExtension:()=>se,readSvgDirectory:()=>x,readSvgFile:()=>O,writeComponentFile:()=>D,writeSvgFile:()=>P});async function O(e){try{return await promises.readFile(e,"utf-8")}catch(r){throw new Error(`Failed to read SVG file: ${e}. ${r}`)}}async function P(e,r){try{await h(path.dirname(e)),await promises.writeFile(e,r,"utf-8");}catch(t){throw new Error(`Failed to write SVG file: ${e}. ${t}`)}}async function D(e,r){try{await h(path.dirname(e)),await promises.writeFile(e,r,"utf-8");}catch(t){throw new Error(`Failed to write component file: ${e}. ${t}`)}}async function x(e,r=false){try{let t=await promises.readdir(e),o=[];for(let n of t){let s=path.join(e,n),a=await promises.stat(s);if(a.isDirectory()&&r){let p=await x(s,r);o.push(...p);}else a.isFile()&&path.extname(n).toLowerCase()===".svg"&&o.push(s);}return o}catch(t){throw new Error(`Failed to read directory: ${e}. ${t}`)}}async function h(e){fs.existsSync(e)||await promises.mkdir(e,{recursive:true});}function se(e,r=true){return e==="react"?r?".tsx":".jsx":".vue"}function ie(e,r,t){return `${r}${t}`}var w=R(()=>{i();});i();i();i();i();var H={plugins:[{name:"preset-default",params:{overrides:{removeViewBox:false,removeTitle:false,removeDesc:false,removeUselessStrokeAndFill:false,convertColors:{currentColor:true,names2hex:true,rgb2hex:true,shorthex:true,shortname:true}}}},"removeDimensions","cleanupNumericValues"]};function C(e,r=H){try{return svgo.optimize(e,r).data}catch(t){throw new Error(`Failed to optimize SVG: ${t}`)}}function J(e){let r=[{name:"preset-default",params:{overrides:{removeViewBox:!e.removeViewBox,removeTitle:!e.removeTitle,removeDesc:!e.removeDesc,removeUselessStrokeAndFill:!e.preserveClasses,convertColors:e.preserveColors?false:{currentColor:true,names2hex:true,rgb2hex:true,shorthex:true,shortname:true}}}},"cleanupNumericValues"];return e.removeDimensions!==false&&r.push("removeDimensions"),{plugins:r}}i();function K(e){let r=e.replace(/\.svg$/i,"");return r=Q(r),u__default.default(r)}function Q(e){let r=e.toLowerCase().replace(/[^a-zA-Z0-9]/g," ");return r=r.replace(/\s+/g," ").trim(),r}function W(e){return u__default.default(e.replace(/[^a-zA-Z0-9]/g," "))}function f(e,r,t){let o=r?u__default.default(r):"",n=t?u__default.default(t):"",s=u__default.default(e);return `${o}${s}${n}`}var g=class{async processSvg(r,t){let{optimize:o=true}=t;return o?C(r):r}generateComponentName(r){let{name:t,prefix:o,suffix:n}=r;return f(t||"Icon",o,n)}generateFilename(r,t,o=true){try{let{getFileExtension:n,getComponentFilename:s}=(w(),M(U)),a=n(t,o);return s("icon.svg",r,a)}catch{return `${r}${{react:o?".tsx":".jsx",vue:".vue"}[t]}`}}};i();function A(e){let{typescript:r=true,memo:t=true,ref:o=true,titleProp:n=true,descProp:s=true,icon:a=true,dimensions:p=false,replaceAttrValues:c={"#000":"currentColor","#000000":"currentColor"},svgProps:l={},expandProps:v=false,nativeProps:z=true,ariaLabelledBy:B=false,ariaHidden:j=false,role:G="img"}=e,b={typescript:r,memo:t,ref:o,titleProp:n,descProp:s,icon:a,dimensions:p,expandProps:v,svgProps:{className:"{className}",...o&&{ref:"{ref}"},...z&&{width:"{width}",height:"{height}",style:"{style}"},...B&&n&&s&&{"aria-labelledby":"{titleId} {descId}"},...j&&{"aria-hidden":"true"},role:G,...l},replaceAttrValues:c,plugins:["@svgr/plugin-svgo","@svgr/plugin-jsx","@svgr/plugin-prettier"]};return b.svgoConfig={plugins:[{name:"preset-default",params:{overrides:{removeViewBox:false,removeTitle:!n,removeDesc:!s,removeUselessStrokeAndFill:false,removeUnusedNS:false,removeUselessDefs:false,convertShapeToPath:false,mergePaths:false,convertColors:false}}},...a&&!p?[{name:"removeAttrs",params:{attrs:["width","height"]}}]:[],...a?["cleanupNumericValues"]:[]]},b}function E(e,r,t){let o=e;return y(o)&&(o=$(o,r)),o}function y(e){return ["linearGradient","radialGradient","pattern","mask","filter","clipPath","marker","symbol","use"].some(t=>e.includes(`<${t}`)||e.includes(`</${t}`))}function $(e,r){let t=`${r.toLowerCase()}_`;return e=e.replace(/id="([^"]+)"/g,`id="${t}$1"`),e=e.replace(/url\(#([^)]+)\)/g,`url(#${t}$1)`),e=e.replace(/href="#([^"]+)"/g,`href="#${t}$1"`),e}var F=class extends g{async convert(r,t={}){try{let o=this.generateComponentName(t),n=await this.processSvg(r,t);y(n)&&(n=$(n,o));let s=A(t),a=await core.transform(n,s,{componentName:o}),p=E(a,o,t),c=this.generateFilename(o,"react",t.typescript??!0);return {code:p,filename:c,componentName:o}}catch(o){throw new Error(`Failed to convert SVG to React: ${o}`)}}};async function ce(e,r={}){return new F().convert(e,r)}i();i();function T(e,r){let{name:t,prefix:o,suffix:n,props:s=true,replaceAttrValues:a={"#000":"currentColor","#000000":"currentColor"}}=r,c=f(t||"Icon",o,n),l=le(e);return l=pe(l,a),me(l)&&(l=ue(l,c)),l=ge(l,s),{code:fe(l,c,r),componentName:c}}function le(e){return e.replace(/<\?xml[^>]*\?>\s*/,"").replace(/<!--[\s\S]*?-->/g,"").replace(/xmlns="[^"]*"/g,"").trim()}function pe(e,r){let t=e;for(let[o,n]of Object.entries(r)){let s=new RegExp(o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),"g");t=t.replace(s,n);}return t}function me(e){return ["linearGradient","radialGradient","pattern","mask","filter","clipPath","marker","symbol","use"].some(t=>e.includes(`<${t}`)||e.includes(`</${t}`))}function ue(e,r){let t=`${r.toLowerCase()}_`;return e=e.replace(/id="([^"]+)"/g,`id="${t}$1"`),e=e.replace(/url\(#([^)]+)\)/g,`url(#${t}$1)`),e=e.replace(/href="#([^"]+)"/g,`href="#${t}$1"`),e}function ge(e,r){return r?e.replace("<svg",'<svg :class="className" :style="style" v-bind="$attrs"'):e}function fe(e,r,t){let{typescript:o,compositionApi:n,props:s}=t,c=`<script${o?' lang="ts"':""}${n?" setup":""}>`;n?s&&(c+=`
1
+ 'use strict';var promises=require('fs/promises'),path=require('path'),fs=require('fs'),core=require('@svgr/core'),svgo=require('svgo');var d=Object.defineProperty;var G=Object.getOwnPropertyDescriptor;var I=Object.getOwnPropertyNames;var k=Object.prototype.hasOwnProperty;var R=(e,r)=>()=>(e&&(r=e(e=0)),r);var q=(e,r)=>{for(var t in r)d(e,t,{get:r[t],enumerable:true});},Z=(e,r,t,o)=>{if(r&&typeof r=="object"||typeof r=="function")for(let n of I(r))!k.call(e,n)&&n!==t&&d(e,n,{get:()=>r[n],enumerable:!(o=G(r,n))||o.enumerable});return e};var _=e=>Z(d({},"__esModule",{value:true}),e);var i=R(()=>{});var D={};q(D,{ensureDir:()=>se,ensureDirectoryExists:()=>v,getComponentFilename:()=>ae,getFileExtension:()=>ie,readSvgDirectory:()=>x,readSvgFile:()=>O,writeComponentFile:()=>A,writeSvgFile:()=>P});async function O(e){try{return await promises.readFile(e,"utf-8")}catch(r){throw new Error(`Failed to read SVG file: ${e}. ${r}`)}}async function P(e,r){try{await v(path.dirname(e)),await promises.writeFile(e,r,"utf-8");}catch(t){throw new Error(`Failed to write SVG file: ${e}. ${t}`)}}async function A(e,r){try{await v(path.dirname(e)),await promises.writeFile(e,r,"utf-8");}catch(t){throw new Error(`Failed to write component file: ${e}. ${t}`)}}async function x(e,r=false){try{let t=await promises.readdir(e),o=[];for(let n of t){let s=path.join(e,n),a=await promises.stat(s);if(a.isDirectory()&&r){let m=await x(s,r);o.push(...m);}else a.isFile()&&path.extname(n).toLowerCase()===".svg"&&o.push(s);}return o}catch(t){throw new Error(`Failed to read directory: ${e}. ${t}`)}}async function v(e){fs.existsSync(e)||await promises.mkdir(e,{recursive:true});}function ie(e,r=true){return e==="react"?r?".tsx":".jsx":".vue"}function ae(e,r,t){return `${r}${t}`}var se,h=R(()=>{i();se=v;});i();i();i();i();var H={plugins:[{name:"preset-default",params:{overrides:{removeViewBox:false,removeTitle:false,removeDesc:false,removeUselessStrokeAndFill:false,convertColors:{currentColor:true,names2hex:true,rgb2hex:true,shorthex:true,shortname:true}}}},"removeDimensions","cleanupNumericValues"]};function C(e,r=H){try{return svgo.optimize(e,r).data}catch(t){throw new Error(`Failed to optimize SVG: ${t}`)}}function J(e){let r=[{name:"preset-default",params:{overrides:{removeViewBox:!e.removeViewBox,removeTitle:!e.removeTitle,removeDesc:!e.removeDesc,removeUselessStrokeAndFill:!e.preserveClasses,convertColors:e.preserveColors?false:{currentColor:true,names2hex:true,rgb2hex:true,shorthex:true,shortname:true}}}},"cleanupNumericValues"];return e.removeDimensions!==false&&r.push("removeDimensions"),{plugins:r}}i();i();var u=e=>e.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*[a-z]*|[A-Z]|[0-9]+[a-z]*/g)?.map(r=>r.charAt(0).toUpperCase()+r.slice(1).toLowerCase()).join("")||"";function K(e){let r=e.replace(/\.svg$/i,"");return r=Q(r),u(r)}function Q(e){let r=e.toLowerCase().replace(/[^a-zA-Z0-9]/g," ");return r=r.replace(/\s+/g," ").trim(),r}function W(e){return u(e.replace(/[^a-zA-Z0-9]/g," "))}function f(e,r,t){let o=r?u(r):"",n=t?u(t):"",s=u(e);return `${o}${s}${n}`}var g=class{async processSvg(r,t){let{optimize:o=true}=t;return o?C(r):r}generateComponentName(r){let{name:t,prefix:o,suffix:n}=r;return f(t||"Icon",o,n)}generateFilename(r,t,o=true){try{let{getFileExtension:n,getComponentFilename:s}=(h(),_(D)),a=n(t,o);return s("icon.svg",r,a)}catch{return `${r}${{react:o?".tsx":".jsx",vue:".vue"}[t]}`}}};i();function z(e){let{typescript:r=true,memo:t=true,ref:o=true,titleProp:n=true,descProp:s=true,icon:a=true,dimensions:m=false,replaceAttrValues:c={"#000":"currentColor","#000000":"currentColor"},svgProps:l={},expandProps:S=false,nativeProps:T=true,ariaLabelledBy:B=false,ariaHidden:L=false,role:j="img"}=e,b={typescript:r,memo:t,ref:o,titleProp:n,descProp:s,icon:a,dimensions:m,expandProps:S,svgProps:{className:"{className}",...o&&{ref:"{ref}"},...T&&{width:"{width}",height:"{height}",style:"{style}"},...B&&n&&s&&{"aria-labelledby":"{titleId} {descId}"},...L&&{"aria-hidden":"true"},role:j,...l},replaceAttrValues:c,plugins:["@svgr/plugin-svgo","@svgr/plugin-jsx","@svgr/plugin-prettier"]};return b.svgoConfig={plugins:[{name:"preset-default",params:{overrides:{removeViewBox:false,removeTitle:!n,removeDesc:!s,removeUselessStrokeAndFill:false,removeUnusedNS:false,removeUselessDefs:false,convertShapeToPath:false,mergePaths:false,convertColors:false}}},...a&&!m?[{name:"removeAttrs",params:{attrs:["width","height"]}}]:[],...a?["cleanupNumericValues"]:[]]},b}function U(e,r,t){let o=e;return w(o)&&(o=$(o,r)),o}function w(e){return ["linearGradient","radialGradient","pattern","mask","filter","clipPath","marker","symbol","use"].some(t=>e.includes(`<${t}`)||e.includes(`</${t}`))}function $(e,r){let t=`${r.toLowerCase()}_`;return e=e.replace(/id="([^"]+)"/g,`id="${t}$1"`),e=e.replace(/url\(#([^)]+)\)/g,`url(#${t}$1)`),e=e.replace(/href="#([^"]+)"/g,`href="#${t}$1"`),e}var y=class extends g{async convert(r,t={}){try{let o=this.generateComponentName(t),n=await this.processSvg(r,t);w(n)&&(n=$(n,o));let s=z(t),a=await core.transform(n,s,{componentName:o}),m=U(a,o,t),c=this.generateFilename(o,"react",t.typescript??!0);return {code:m,filename:c,componentName:o}}catch(o){throw new Error(`Failed to convert SVG to React: ${o}`)}}};async function le(e,r={}){return new y().convert(e,r)}i();i();function E(e,r){let{name:t,prefix:o,suffix:n,props:s=true,replaceAttrValues:a={"#000":"currentColor","#000000":"currentColor"}}=r,c=f(t||"Icon",o,n),l=pe(e);return l=me(l,a),ue(l)&&(l=ge(l,c)),l=fe(l,s),{code:ve(l,c,r),componentName:c}}function pe(e){return e.replace(/<\?xml[^>]*\?>\s*/,"").replace(/<!--[\s\S]*?-->/g,"").replace(/xmlns="[^"]*"/g,"").trim()}function me(e,r){let t=e;for(let[o,n]of Object.entries(r)){let s=new RegExp(o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),"g");t=t.replace(s,n);}return t}function ue(e){return ["linearGradient","radialGradient","pattern","mask","filter","clipPath","marker","symbol","use"].some(t=>e.includes(`<${t}`)||e.includes(`</${t}`))}function ge(e,r){let t=`${r.toLowerCase()}_`;return e=e.replace(/id="([^"]+)"/g,`id="${t}$1"`),e=e.replace(/url\(#([^)]+)\)/g,`url(#${t}$1)`),e=e.replace(/href="#([^"]+)"/g,`href="#${t}$1"`),e}function fe(e,r){return r?e.replace("<svg",'<svg :class="className" :style="style" v-bind="$attrs"'):e}function ve(e,r,t){let{typescript:o,compositionApi:n,props:s}=t,c=`<script${o?' lang="ts"':""}${n?" setup":""}>`;n?s&&(c+=`
2
2
  interface Props {
3
3
  className?: string;
4
4
  style?: Record<string, any>;
@@ -16,8 +16,5 @@ export default {
16
16
  `,c+="</script>";let l=`
17
17
  <template>
18
18
  ${e}
19
- </template>`;return [c,l,`
20
- <style scoped>
21
- /* Component styles */
22
- </style>`].filter(Boolean).join(`
23
- `)}var S=class extends g{async convert(r,t={}){try{let o=await this.processSvg(r,t),{code:n,componentName:s}=T(o,t),a=this.generateFilename(s,"vue",t.typescript??!0);return {code:n,filename:a,componentName:s}}catch(o){throw new Error(`Failed to convert SVG to Vue: ${o}`)}}};async function ve(e,r={}){return new S().convert(e,r)}w();Object.defineProperty(exports,"pascalCase",{enumerable:true,get:function(){return u__default.default}});exports.convertToReact=ce;exports.convertToVue=ve;exports.createSvgoConfig=J;exports.formatComponentName=f;exports.optimizeSvg=C;exports.readSvgDirectory=x;exports.readSvgFile=O;exports.sanitizeComponentName=W;exports.svgToComponentName=K;exports.writeComponentFile=D;exports.writeSvgFile=P;
19
+ </template>`;return [c,l].filter(Boolean).join(`
20
+ `)}var F=class extends g{async convert(r,t={}){try{let o=await this.processSvg(r,t),{code:n,componentName:s}=E(o,t),a=this.generateFilename(s,"vue",t.typescript??!0);return {code:n,filename:a,componentName:s}}catch(o){throw new Error(`Failed to convert SVG to Vue: ${o}`)}}};async function de(e,r={}){return new F().convert(e,r)}h();exports.convertToReact=le;exports.convertToVue=de;exports.createSvgoConfig=J;exports.formatComponentName=f;exports.optimizeSvg=C;exports.pascalCase=u;exports.readSvgDirectory=x;exports.readSvgFile=O;exports.sanitizeComponentName=W;exports.svgToComponentName=K;exports.writeComponentFile=A;exports.writeSvgFile=P;
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import {dirname,join,extname}from'path';import'url';import {readFile,writeFile,readdir,stat,mkdir}from'fs/promises';import {existsSync}from'fs';import {transform}from'@svgr/core';import {optimize}from'svgo';import g from'just-pascal-case';export{default as pascalCase}from'just-pascal-case';var C=Object.defineProperty;var L=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var I=Object.prototype.hasOwnProperty;var N=(e,r)=>()=>(e&&(r=e(e=0)),r);var q=(e,r)=>{for(var t in r)C(e,t,{get:r[t],enumerable:true});},Z=(e,r,t,o)=>{if(r&&typeof r=="object"||typeof r=="function")for(let n of _(r))!I.call(e,n)&&n!==t&&C(e,n,{get:()=>r[n],enumerable:!(o=L(r,n))||o.enumerable});return e};var H=e=>Z(C({},"__esModule",{value:true}),e);var i=N(()=>{});var A={};q(A,{ensureDirectoryExists:()=>w,getComponentFilename:()=>ae,getFileExtension:()=>ie,readSvgDirectory:()=>h,readSvgFile:()=>O,writeComponentFile:()=>T,writeSvgFile:()=>D});async function O(e){try{return await readFile(e,"utf-8")}catch(r){throw new Error(`Failed to read SVG file: ${e}. ${r}`)}}async function D(e,r){try{await w(dirname(e)),await writeFile(e,r,"utf-8");}catch(t){throw new Error(`Failed to write SVG file: ${e}. ${t}`)}}async function T(e,r){try{await w(dirname(e)),await writeFile(e,r,"utf-8");}catch(t){throw new Error(`Failed to write component file: ${e}. ${t}`)}}async function h(e,r=false){try{let t=await readdir(e),o=[];for(let n of t){let s=join(e,n),a=await stat(s);if(a.isDirectory()&&r){let p=await h(s,r);o.push(...p);}else a.isFile()&&extname(n).toLowerCase()===".svg"&&o.push(s);}return o}catch(t){throw new Error(`Failed to read directory: ${e}. ${t}`)}}async function w(e){existsSync(e)||await mkdir(e,{recursive:true});}function ie(e,r=true){return e==="react"?r?".tsx":".jsx":".vue"}function ae(e,r,t){return `${r}${t}`}var y=N(()=>{i();});i();i();i();i();var K={plugins:[{name:"preset-default",params:{overrides:{removeViewBox:false,removeTitle:false,removeDesc:false,removeUselessStrokeAndFill:false,convertColors:{currentColor:true,names2hex:true,rgb2hex:true,shorthex:true,shortname:true}}}},"removeDimensions","cleanupNumericValues"]};function x(e,r=K){try{return optimize(e,r).data}catch(t){throw new Error(`Failed to optimize SVG: ${t}`)}}function M(e){let r=[{name:"preset-default",params:{overrides:{removeViewBox:!e.removeViewBox,removeTitle:!e.removeTitle,removeDesc:!e.removeDesc,removeUselessStrokeAndFill:!e.preserveClasses,convertColors:e.preserveColors?false:{currentColor:true,names2hex:true,rgb2hex:true,shorthex:true,shortname:true}}}},"cleanupNumericValues"];return e.removeDimensions!==false&&r.push("removeDimensions"),{plugins:r}}i();function Q(e){let r=e.replace(/\.svg$/i,"");return r=W(r),g(r)}function W(e){let r=e.toLowerCase().replace(/[^a-zA-Z0-9]/g," ");return r=r.replace(/\s+/g," ").trim(),r}function X(e){return g(e.replace(/[^a-zA-Z0-9]/g," "))}function v(e,r,t){let o=r?g(r):"",n=t?g(t):"",s=g(e);return `${o}${s}${n}`}var f=class{async processSvg(r,t){let{optimize:o=true}=t;return o?x(r):r}generateComponentName(r){let{name:t,prefix:o,suffix:n}=r;return v(t||"Icon",o,n)}generateFilename(r,t,o=true){try{let{getFileExtension:n,getComponentFilename:s}=(y(),H(A)),a=n(t,o);return s("icon.svg",r,a)}catch{return `${r}${{react:o?".tsx":".jsx",vue:".vue"}[t]}`}}};i();function E(e){let{typescript:r=true,memo:t=true,ref:o=true,titleProp:n=true,descProp:s=true,icon:a=true,dimensions:p=false,replaceAttrValues:c={"#000":"currentColor","#000000":"currentColor"},svgProps:l={},expandProps:d=false,nativeProps:G=true,ariaLabelledBy:U=false,ariaHidden:j=false,role:k="img"}=e,V={typescript:r,memo:t,ref:o,titleProp:n,descProp:s,icon:a,dimensions:p,expandProps:d,svgProps:{className:"{className}",...o&&{ref:"{ref}"},...G&&{width:"{width}",height:"{height}",style:"{style}"},...U&&n&&s&&{"aria-labelledby":"{titleId} {descId}"},...j&&{"aria-hidden":"true"},role:k,...l},replaceAttrValues:c,plugins:["@svgr/plugin-svgo","@svgr/plugin-jsx","@svgr/plugin-prettier"]};return V.svgoConfig={plugins:[{name:"preset-default",params:{overrides:{removeViewBox:false,removeTitle:!n,removeDesc:!s,removeUselessStrokeAndFill:false,removeUnusedNS:false,removeUselessDefs:false,convertShapeToPath:false,mergePaths:false,convertColors:false}}},...a&&!p?[{name:"removeAttrs",params:{attrs:["width","height"]}}]:[],...a?["cleanupNumericValues"]:[]]},V}function z(e,r,t){let o=e;return $(o)&&(o=F(o,r)),o}function $(e){return ["linearGradient","radialGradient","pattern","mask","filter","clipPath","marker","symbol","use"].some(t=>e.includes(`<${t}`)||e.includes(`</${t}`))}function F(e,r){let t=`${r.toLowerCase()}_`;return e=e.replace(/id="([^"]+)"/g,`id="${t}$1"`),e=e.replace(/url\(#([^)]+)\)/g,`url(#${t}$1)`),e=e.replace(/href="#([^"]+)"/g,`href="#${t}$1"`),e}var S=class extends f{async convert(r,t={}){try{let o=this.generateComponentName(t),n=await this.processSvg(r,t);$(n)&&(n=F(n,o));let s=E(t),a=await transform(n,s,{componentName:o}),p=z(a,o,t),c=this.generateFilename(o,"react",t.typescript??!0);return {code:p,filename:c,componentName:o}}catch(o){throw new Error(`Failed to convert SVG to React: ${o}`)}}};async function le(e,r={}){return new S().convert(e,r)}i();i();function B(e,r){let{name:t,prefix:o,suffix:n,props:s=true,replaceAttrValues:a={"#000":"currentColor","#000000":"currentColor"}}=r,c=v(t||"Icon",o,n),l=pe(e);return l=me(l,a),ue(l)&&(l=ge(l,c)),l=fe(l,s),{code:ve(l,c,r),componentName:c}}function pe(e){return e.replace(/<\?xml[^>]*\?>\s*/,"").replace(/<!--[\s\S]*?-->/g,"").replace(/xmlns="[^"]*"/g,"").trim()}function me(e,r){let t=e;for(let[o,n]of Object.entries(r)){let s=new RegExp(o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),"g");t=t.replace(s,n);}return t}function ue(e){return ["linearGradient","radialGradient","pattern","mask","filter","clipPath","marker","symbol","use"].some(t=>e.includes(`<${t}`)||e.includes(`</${t}`))}function ge(e,r){let t=`${r.toLowerCase()}_`;return e=e.replace(/id="([^"]+)"/g,`id="${t}$1"`),e=e.replace(/url\(#([^)]+)\)/g,`url(#${t}$1)`),e=e.replace(/href="#([^"]+)"/g,`href="#${t}$1"`),e}function fe(e,r){return r?e.replace("<svg",'<svg :class="className" :style="style" v-bind="$attrs"'):e}function ve(e,r,t){let{typescript:o,compositionApi:n,props:s}=t,c=`<script${o?' lang="ts"':""}${n?" setup":""}>`;n?s&&(c+=`
1
+ import {dirname,join,extname}from'path';import'url';import {readFile,writeFile,readdir,stat,mkdir}from'fs/promises';import {existsSync}from'fs';import {transform}from'@svgr/core';import {optimize}from'svgo';var d=Object.defineProperty;var k=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var I=Object.prototype.hasOwnProperty;var N=(e,r)=>()=>(e&&(r=e(e=0)),r);var q=(e,r)=>{for(var t in r)d(e,t,{get:r[t],enumerable:true});},Z=(e,r,t,o)=>{if(r&&typeof r=="object"||typeof r=="function")for(let n of _(r))!I.call(e,n)&&n!==t&&d(e,n,{get:()=>r[n],enumerable:!(o=k(r,n))||o.enumerable});return e};var H=e=>Z(d({},"__esModule",{value:true}),e);var i=N(()=>{});var z={};q(z,{ensureDir:()=>ie,ensureDirectoryExists:()=>C,getComponentFilename:()=>ce,getFileExtension:()=>ae,readSvgDirectory:()=>h,readSvgFile:()=>O,writeComponentFile:()=>D,writeSvgFile:()=>A});async function O(e){try{return await readFile(e,"utf-8")}catch(r){throw new Error(`Failed to read SVG file: ${e}. ${r}`)}}async function A(e,r){try{await C(dirname(e)),await writeFile(e,r,"utf-8");}catch(t){throw new Error(`Failed to write SVG file: ${e}. ${t}`)}}async function D(e,r){try{await C(dirname(e)),await writeFile(e,r,"utf-8");}catch(t){throw new Error(`Failed to write component file: ${e}. ${t}`)}}async function h(e,r=false){try{let t=await readdir(e),o=[];for(let n of t){let s=join(e,n),a=await stat(s);if(a.isDirectory()&&r){let u=await h(s,r);o.push(...u);}else a.isFile()&&extname(n).toLowerCase()===".svg"&&o.push(s);}return o}catch(t){throw new Error(`Failed to read directory: ${e}. ${t}`)}}async function C(e){existsSync(e)||await mkdir(e,{recursive:true});}function ae(e,r=true){return e==="react"?r?".tsx":".jsx":".vue"}function ce(e,r,t){return `${r}${t}`}var ie,w=N(()=>{i();ie=C;});i();i();i();i();var K={plugins:[{name:"preset-default",params:{overrides:{removeViewBox:false,removeTitle:false,removeDesc:false,removeUselessStrokeAndFill:false,convertColors:{currentColor:true,names2hex:true,rgb2hex:true,shorthex:true,shortname:true}}}},"removeDimensions","cleanupNumericValues"]};function x(e,r=K){try{return optimize(e,r).data}catch(t){throw new Error(`Failed to optimize SVG: ${t}`)}}function M(e){let r=[{name:"preset-default",params:{overrides:{removeViewBox:!e.removeViewBox,removeTitle:!e.removeTitle,removeDesc:!e.removeDesc,removeUselessStrokeAndFill:!e.preserveClasses,convertColors:e.preserveColors?false:{currentColor:true,names2hex:true,rgb2hex:true,shorthex:true,shortname:true}}}},"cleanupNumericValues"];return e.removeDimensions!==false&&r.push("removeDimensions"),{plugins:r}}i();i();var g=e=>e.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*[a-z]*|[A-Z]|[0-9]+[a-z]*/g)?.map(r=>r.charAt(0).toUpperCase()+r.slice(1).toLowerCase()).join("")||"";function Q(e){let r=e.replace(/\.svg$/i,"");return r=W(r),g(r)}function W(e){let r=e.toLowerCase().replace(/[^a-zA-Z0-9]/g," ");return r=r.replace(/\s+/g," ").trim(),r}function X(e){return g(e.replace(/[^a-zA-Z0-9]/g," "))}function v(e,r,t){let o=r?g(r):"",n=t?g(t):"",s=g(e);return `${o}${s}${n}`}var f=class{async processSvg(r,t){let{optimize:o=true}=t;return o?x(r):r}generateComponentName(r){let{name:t,prefix:o,suffix:n}=r;return v(t||"Icon",o,n)}generateFilename(r,t,o=true){try{let{getFileExtension:n,getComponentFilename:s}=(w(),H(z)),a=n(t,o);return s("icon.svg",r,a)}catch{return `${r}${{react:o?".tsx":".jsx",vue:".vue"}[t]}`}}};i();function T(e){let{typescript:r=true,memo:t=true,ref:o=true,titleProp:n=true,descProp:s=true,icon:a=true,dimensions:u=false,replaceAttrValues:c={"#000":"currentColor","#000000":"currentColor"},svgProps:l={},expandProps:b=false,nativeProps:U=true,ariaLabelledBy:G=false,ariaHidden:L=false,role:j="img"}=e,V={typescript:r,memo:t,ref:o,titleProp:n,descProp:s,icon:a,dimensions:u,expandProps:b,svgProps:{className:"{className}",...o&&{ref:"{ref}"},...U&&{width:"{width}",height:"{height}",style:"{style}"},...G&&n&&s&&{"aria-labelledby":"{titleId} {descId}"},...L&&{"aria-hidden":"true"},role:j,...l},replaceAttrValues:c,plugins:["@svgr/plugin-svgo","@svgr/plugin-jsx","@svgr/plugin-prettier"]};return V.svgoConfig={plugins:[{name:"preset-default",params:{overrides:{removeViewBox:false,removeTitle:!n,removeDesc:!s,removeUselessStrokeAndFill:false,removeUnusedNS:false,removeUselessDefs:false,convertShapeToPath:false,mergePaths:false,convertColors:false}}},...a&&!u?[{name:"removeAttrs",params:{attrs:["width","height"]}}]:[],...a?["cleanupNumericValues"]:[]]},V}function E(e,r,t){let o=e;return $(o)&&(o=y(o,r)),o}function $(e){return ["linearGradient","radialGradient","pattern","mask","filter","clipPath","marker","symbol","use"].some(t=>e.includes(`<${t}`)||e.includes(`</${t}`))}function y(e,r){let t=`${r.toLowerCase()}_`;return e=e.replace(/id="([^"]+)"/g,`id="${t}$1"`),e=e.replace(/url\(#([^)]+)\)/g,`url(#${t}$1)`),e=e.replace(/href="#([^"]+)"/g,`href="#${t}$1"`),e}var F=class extends f{async convert(r,t={}){try{let o=this.generateComponentName(t),n=await this.processSvg(r,t);$(n)&&(n=y(n,o));let s=T(t),a=await transform(n,s,{componentName:o}),u=E(a,o,t),c=this.generateFilename(o,"react",t.typescript??!0);return {code:u,filename:c,componentName:o}}catch(o){throw new Error(`Failed to convert SVG to React: ${o}`)}}};async function pe(e,r={}){return new F().convert(e,r)}i();i();function B(e,r){let{name:t,prefix:o,suffix:n,props:s=true,replaceAttrValues:a={"#000":"currentColor","#000000":"currentColor"}}=r,c=v(t||"Icon",o,n),l=me(e);return l=ue(l,a),ge(l)&&(l=fe(l,c)),l=ve(l,s),{code:Ce(l,c,r),componentName:c}}function me(e){return e.replace(/<\?xml[^>]*\?>\s*/,"").replace(/<!--[\s\S]*?-->/g,"").replace(/xmlns="[^"]*"/g,"").trim()}function ue(e,r){let t=e;for(let[o,n]of Object.entries(r)){let s=new RegExp(o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),"g");t=t.replace(s,n);}return t}function ge(e){return ["linearGradient","radialGradient","pattern","mask","filter","clipPath","marker","symbol","use"].some(t=>e.includes(`<${t}`)||e.includes(`</${t}`))}function fe(e,r){let t=`${r.toLowerCase()}_`;return e=e.replace(/id="([^"]+)"/g,`id="${t}$1"`),e=e.replace(/url\(#([^)]+)\)/g,`url(#${t}$1)`),e=e.replace(/href="#([^"]+)"/g,`href="#${t}$1"`),e}function ve(e,r){return r?e.replace("<svg",'<svg :class="className" :style="style" v-bind="$attrs"'):e}function Ce(e,r,t){let{typescript:o,compositionApi:n,props:s}=t,c=`<script${o?' lang="ts"':""}${n?" setup":""}>`;n?s&&(c+=`
2
2
  interface Props {
3
3
  className?: string;
4
4
  style?: Record<string, any>;
@@ -16,8 +16,5 @@ export default {
16
16
  `,c+="</script>";let l=`
17
17
  <template>
18
18
  ${e}
19
- </template>`;return [c,l,`
20
- <style scoped>
21
- /* Component styles */
22
- </style>`].filter(Boolean).join(`
23
- `)}var b=class extends f{async convert(r,t={}){try{let o=await this.processSvg(r,t),{code:n,componentName:s}=B(o,t),a=this.generateFilename(s,"vue",t.typescript??!0);return {code:n,filename:a,componentName:s}}catch(o){throw new Error(`Failed to convert SVG to Vue: ${o}`)}}};async function de(e,r={}){return new b().convert(e,r)}y();export{le as convertToReact,de as convertToVue,M as createSvgoConfig,v as formatComponentName,x as optimizeSvg,h as readSvgDirectory,O as readSvgFile,X as sanitizeComponentName,Q as svgToComponentName,T as writeComponentFile,D as writeSvgFile};
19
+ </template>`;return [c,l].filter(Boolean).join(`
20
+ `)}var S=class extends f{async convert(r,t={}){try{let o=await this.processSvg(r,t),{code:n,componentName:s}=B(o,t),a=this.generateFilename(s,"vue",t.typescript??!0);return {code:n,filename:a,componentName:s}}catch(o){throw new Error(`Failed to convert SVG to Vue: ${o}`)}}};async function de(e,r={}){return new S().convert(e,r)}w();export{pe as convertToReact,de as convertToVue,M as createSvgoConfig,v as formatComponentName,x as optimizeSvg,g as pascalCase,h as readSvgDirectory,O as readSvgFile,X as sanitizeComponentName,Q as svgToComponentName,D as writeComponentFile,A as writeSvgFile};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svgfusion",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "A powerful CLI tool and library that converts SVG files into production-ready React and Vue 3 components with TypeScript support and automatic optimization.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -90,13 +90,13 @@
90
90
  "chalk": "^5.0.0",
91
91
  "commander": "^11.0.0",
92
92
  "figlet": "^1.8.1",
93
- "just-pascal-case": "^3.2.0",
94
93
  "ora": "^7.0.0",
95
94
  "svgo": "^3.0.0"
96
95
  },
97
96
  "devDependencies": {
98
97
  "@commitlint/cli": "^17.8.1",
99
98
  "@commitlint/config-conventional": "^17.8.1",
99
+ "@jest/globals": "^30.0.4",
100
100
  "@semantic-release/changelog": "^6.0.3",
101
101
  "@semantic-release/git": "^10.0.1",
102
102
  "@semantic-release/github": "^11.0.3",